The Query Service (QS) is an integral component of the Snickerdoodle Protocol Core package. The QS responsible for processing queries emitted from consent contracts that the Data Wallet user has opted in to (i.e. the user's Data Wallet address has a non-zero balance in the associated consent contract). The primary components of the Query Service of interest to contributors are:
graph TD;
CC[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/contracts/contracts/consent/Consent.sol'>Concent Contract</a>]
DW[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/SnickerdoodleCore.ts'>Snickerdoodle Core Service</a>]
QR[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/QueryService.ts'>Query Service</a>]
ASTE[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/QueryService.ts'>AST Evaluator</a>]
PL[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/persistence/src/DataWalletPersistence.ts'>Persistence Layer</a>]
AS[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/README.md#high-level-architecture'>Aggregation Service</a>]
CC-->|requestForData event|DW;
DW-->|detect requestForData & CID|QR;
QR-->|parse query contents|ASTE-->|permissioned access|PL;
PL-->|SDQL callback url|AS
Processing a blockchain query begins with the detection, by an instance of BlockchainLister
, of a
requestForData
event emitted from a consent contract. The event data includes an IPFS
CID pointing to a SDQL JSON file pinned to the IPFS network containing the query to be executed.
The query CID is then passed into the Query Service via a call to approveQuery
.
The call to approveQuery
then creates one abstract syntax tree (AST) for each and every logic expression in the logic
block of given query file.
The following logic block results in 3 AST roots.
logic: {
ads: ["if$q1>30then$a1"],
compensations: [
"if$q2then$c1",
"if$a1then$c2",
],
},
These logic expressions can reference one or more
queries
,ads
,compensations
- and
returns
.
Given example references $q1, $q2 as queries, $a1 as an ad, and $c1, $c2 as compensations.
Resulting ASTs are ultimately evaluated against data wallet's persistence layer, in consistence with user-specified permissions (i.e. if a query
specification requires access to the location
attribute of a user, the user must have consented to this access by indicating their acceptance in the consent contract associated with the query.)
Finally, after data has been accessed at the persistence layer level, the approveQuery
function delivers a cryptographically signed data payload, via the deliverInsights
function to the aggregation url specified the query's SDQL JSON file.
flowchart TD;
QS[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/QueryService.ts'>Query Service</a>]
QPE[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/feature/query-engine-docs/packages/core/src/implementations/business/utilities/QueryParsingEngine.ts'>Query Parsing Engine</a>]
ASTE[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/QueryService.ts'>AST Evaluator</a>]
QR[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/utilities/query/QueryRepository.ts'>Query Repository - Cache</a>]
QEVAL[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/core/src/implementations/business/utilities/query/QueryEvaluator.ts'>Query Evaluator</a>]
PL[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/develop/packages/persistence/src/DataWalletPersistence.ts'>Persistence Layer</a>]
IP[<a href='https://github.com/SnickerdoodleLabs/protocol/blob/feature/query-engine-docs/packages/core/src/implementations/data/InsightPlatformRepository.ts'>Insight Platform</a>]
QS--"1. SDQLQuery"-->QPE;
QPE--"[insights, rewards]"-->QS;
QS--2. deliver insights--> IP;
QPE-- 1.1. query schema --> SDQLParser--ASTs and required permissions-->QPE;
QPE--"1.2. (logic expression, ast)"-->Permission{"Has permission \n on queries needed?"}
Permission--yes-->ASTE--1. query objects -->QR;
Permission--"no (null result)"-->Result;
ASTE--2. result -->Result;
Result-->QPE;
QR --> Cache{"In cache?"}
Cache -- Yes --> QR
Cache -- No --> QEVAL -- permissions --> PL
QEVAL -- Data --> QR
- if($q1and$q2and$q3)then$r1else$r2
graph TD;
IF-->TrueExpr-->r1;
IF-->ConditionExpr;
IF-->FalseExpr-->r2;
ConditionExpr --> And1;
And1 --> BoolExpr4;
BoolExpr4 --> And2;
And1 --> BoolExpr3;
BoolExpr3 --> q3;
And2-->BoolExpr1;
And2-->BoolExpr2;
BoolExpr1 --> q1;
BoolExpr2 --> q2;
We traverse the tree in post-order (evaluate children first in any order).
- if(condition)thenTrueExpr --> condition, if, TrueExpr, then
- if(condition)thenTrueExprElseFalseExpr --> condition, if, TrueExpr, then, FalseExpr, else
- $q1and$q2 -> $q1,$q2,and
- $q1and$q2or$q3 -> $q1,$q2,and,q3,or
- ($q1and($q2or$q3)) -> $q1,$q2,q3,or,and
- if$q1and$q2then$r1 -> $q1, $q2, and, if, $r1, then
- if($q1>=30)and($q2<=35)then$a1 -> $q1, 30, >, $q2, 35, <, and, $a1, if