@@ -4,130 +4,148 @@ import {
44 BigInt ,
55 Bytes ,
66 DataSourceContext ,
7+ store ,
8+ log ,
79} from "@graphprotocol/graph-ts" ;
810import { TestEvent } from "../generated/Contract/Contract" ;
9- import { IpfsFile , IpfsFile1 , SpawnTestEntity } from "../generated/schema" ;
10-
11- // CID of `file-data-sources/abis/Contract.abi` after being processed by graph-cli.
12- const KNOWN_CID = "QmQ2REmceVtzawp7yrnxLQXgNNCtFHEnig6fL9aqE1kcWq" ;
13-
14- export function handleBlock ( block : ethereum . Block ) : void {
15- let entity = new IpfsFile ( "onchain" ) ;
16- entity . content = "onchain" ;
17- entity . save ( ) ;
18-
19- // This will create the same data source twice, once at block 0 and another at block 2.
20- // The creation at block 2 should be detected as a duplicate and therefore a noop.
21- if ( block . number == BigInt . fromI32 ( 0 ) || block . number == BigInt . fromI32 ( 2 ) ) {
22- dataSource . create ( "File" , [ KNOWN_CID ] ) ;
11+ import { FileEntity , Foo } from "../generated/schema" ;
12+
13+ const ONCHAIN_FROM_OFFCHAIN = "CREATE_ONCHAIN_DATASOURCE_FROM_OFFCHAIN_HANDLER" ;
14+ const CREATE_FILE = "CREATE_FILE" ;
15+ // const CREATE_FILE_FROM_HANDLE_FILE = "CREATE_FILE_FROM_HANDLE_FILE";
16+ const CREATE_UNDEFINED_ENTITY = "CREATE_UNDEFINED_ENTITY" ;
17+ const CREATE_CONFLICTING_ENTITY = "CREATE_CONFLICTING_ENTITY" ;
18+ const SPAWN_FDS_FROM_OFFCHAIN_HANDLER = "SPAWN_FDS_FROM_OFFCHAIN_HANDLER" ;
19+ const ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER =
20+ "ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER" ;
21+ const ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD =
22+ "ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD" ;
23+
24+ const CREATE_FOO = "CREATE_FOO" ;
25+ export function handleTestEvent ( event : TestEvent ) : void {
26+ if ( event . params . testCommand == CREATE_FILE ) {
27+ dataSource . createWithContext (
28+ "File" ,
29+ [ event . params . data ] ,
30+ new DataSourceContext ( ) ,
31+ ) ;
2332 }
2433
25- if ( block . number == BigInt . fromI32 ( 1 ) ) {
26- let entity = IpfsFile . load ( "onchain" ) ! ;
27- assert ( entity . content == "onchain" ) ;
28-
29- // The test assumes file data sources are processed in the block in which they are created.
30- // So the ds created at block 0 will have been processed.
31- //
32- // Test that onchain data sources cannot read offchain data.
33- assert ( IpfsFile . load ( KNOWN_CID ) == null ) ;
34+ if ( event . params . testCommand == SPAWN_FDS_FROM_OFFCHAIN_HANDLER ) {
35+ let comma_separated_hash = event . params . data ;
36+ let hash1 = comma_separated_hash . split ( "," ) [ 0 ] ;
37+ let hash2 = comma_separated_hash . split ( "," ) [ 1 ] ;
38+ let context = new DataSourceContext ( ) ;
39+ context . setString ( "command" , SPAWN_FDS_FROM_OFFCHAIN_HANDLER ) ;
40+ context . setString ( "hash" , hash2 ) ;
3441
35- // Test that using an invalid CID will be ignored
36- dataSource . create ( "File" , [ "hi, I'm not valid" ] ) ;
42+ log . info (
43+ "Creating file data source from handleFile, command : {} ,hash1: {}, hash2: {}" ,
44+ [ SPAWN_FDS_FROM_OFFCHAIN_HANDLER , hash1 , hash2 ] ,
45+ ) ;
46+ dataSource . createWithContext ( "File" , [ hash1 ] , context ) ;
3747 }
3848
39- // This will invoke File1 data source with same CID, which will be used
40- // to test whether same cid is triggered across different data source.
41- if ( block . number == BigInt . fromI32 ( 3 ) ) {
42- // Test that onchain data sources cannot read offchain data (again, but this time more likely to hit the DB than the write queue).
43- assert ( IpfsFile . load ( KNOWN_CID ) == null ) ;
44-
45- dataSource . create ( "File1" , [ KNOWN_CID ] ) ;
49+ if ( event . params . testCommand == ONCHAIN_FROM_OFFCHAIN ) {
50+ let context = new DataSourceContext ( ) ;
51+ context . setString ( "command" , ONCHAIN_FROM_OFFCHAIN ) ;
52+ context . setString ( "address" , "0x0000000000000000000000000000000000000000" ) ;
53+ dataSource . createWithContext ( "File" , [ event . params . data ] , context ) ;
4654 }
47- }
4855
49- export function handleTestEvent ( event : TestEvent ) : void {
50- let command = event . params . testCommand ;
51-
52- if ( command == "createFile2" ) {
53- // Will fail the subgraph when processed due to mismatch in the entity type and 'entities'.
54- dataSource . create ( "File2" , [ KNOWN_CID ] ) ;
55- } else if ( command == "saveConflictingEntity" ) {
56- // Will fail the subgraph because the same entity has been created in a file data source.
57- let entity = new IpfsFile ( KNOWN_CID ) ;
58- entity . content = "empty" ;
59- entity . save ( ) ;
60- } else if ( command == "createFile1" ) {
61- // Will fail the subgraph with a conflict between two entities created by offchain data sources.
62- let context = new DataSourceContext ( ) ;
63- context . setBytes ( "hash" , event . block . hash ) ;
64- dataSource . createWithContext ( "File1" , [ KNOWN_CID ] , context ) ;
65- } else if ( command == "spawnOffChainHandlerTest" ) {
66- // Used to test the spawning of a file data source from another file data source handler.
67- // `SpawnTestHandler` will spawn a file data source that will be handled by `spawnOffChainHandlerTest`,
68- // which creates another file data source `OffChainDataSource`, which will be handled by `handleSpawnedTest`.
56+ if ( event . params . testCommand == CREATE_UNDEFINED_ENTITY ) {
57+ log . info ( "Creating undefined entity" , [ ] ) ;
6958 let context = new DataSourceContext ( ) ;
70- context . setString ( "command" , command ) ;
71- dataSource . createWithContext ( "SpawnTestHandler" , [ KNOWN_CID ] , context ) ;
72- } else if ( command == "spawnOnChainHandlerTest" ) {
73- // Used to test the failure of spawning of on-chain data source from a file data source handler.
74- // `SpawnTestHandler` will spawn a file data source that will be handled by `spawnTestHandler`,
75- // which creates an `OnChainDataSource`, which should fail since spawning onchain datasources
76- // from offchain handlers is not allowed.
77- let context = new DataSourceContext ( ) ;
78- context . setString ( "command" , command ) ;
79- dataSource . createWithContext ( "SpawnTestHandler" , [ KNOWN_CID ] , context ) ;
80- } else {
81- assert ( false , "Unknown command: " + command ) ;
59+ context . setString ( "command" , CREATE_UNDEFINED_ENTITY ) ;
60+ dataSource . createWithContext ( "File" , [ event . params . data ] , context ) ;
8261 }
83- }
8462
85- export function handleFile ( data : Bytes ) : void {
86- // Test that offchain data sources cannot read onchain data.
87- assert ( IpfsFile . load ( "onchain" ) == null ) ;
63+ if ( event . params . testCommand == CREATE_CONFLICTING_ENTITY ) {
64+ log . info ( "Creating conflicting entity" , [ ] ) ;
65+ let entity = new FileEntity ( event . params . data ) ;
66+ entity . content = "content" ;
67+ entity . save ( ) ;
68+ }
8869
8970 if (
90- dataSource . stringParam ( ) != "QmVkvoPGi9jvvuxsHDVJDgzPEzagBaWSZRYoRDzU244HjZ"
71+ event . params . testCommand ==
72+ ACCESS_AND_UPDATE_OFFCHAIN_ENTITY_IN_ONCHAIN_HANDLER
9173 ) {
92- // Test that an offchain data source cannot read from another offchain data source.
93- assert (
94- IpfsFile . load ( "QmVkvoPGi9jvvuxsHDVJDgzPEzagBaWSZRYoRDzU244HjZ" ) == null
95- ) ;
74+ let hash = event . params . data ;
75+ log . info ( "Creating file data source from handleFile: {}" , [ hash ] ) ;
76+ let entity = FileEntity . load ( event . params . data ) ;
77+ if ( entity == null ) {
78+ log . info ( "Entity not found" , [ ] ) ;
79+ } else {
80+ // This should never be logged if the entity was created in the offchain handler
81+ // Such entities are not accessible in onchain handlers and will return null on load
82+ log . info ( "Updating entity content" , [ ] ) ;
83+ entity . content = "updated content" ;
84+ entity . save ( ) ;
85+ }
9686 }
9787
98- let entity = new IpfsFile ( dataSource . stringParam ( ) ) ;
99- entity . content = data . toString ( ) ;
100- entity . save ( ) ;
101-
102- // Test that an offchain data source can load its own entities
103- let loaded_entity = IpfsFile . load ( dataSource . stringParam ( ) ) ! ;
104- assert ( loaded_entity . content == entity . content ) ;
105- }
88+ if ( event . params . testCommand == CREATE_FOO ) {
89+ let entity = new Foo ( event . params . data ) ;
90+ entity . save ( ) ;
91+ let context = new DataSourceContext ( ) ;
92+ context . setString ( "command" , CREATE_FOO ) ;
93+ dataSource . createWithContext ( "File" , [ event . params . data ] , context ) ;
94+ }
10695
107- export function handleFile1 ( data : Bytes ) : void {
108- let entity = new IpfsFile1 ( dataSource . stringParam ( ) ) ;
109- entity . content = data . toString ( ) ;
110- entity . save ( ) ;
111- }
96+ if ( event . params . testCommand == ACCESS_FILE_ENTITY_THROUGH_DERIVED_FIELD ) {
97+ let entity = Foo . load ( event . params . data ) ;
98+ if ( entity == null ) {
99+ log . info ( "Entity not found" , [ ] ) ;
100+ } else {
101+ log . info ( "Accessing file entity through derived field" , [ ] ) ;
102+ let fileEntity = entity . ipfs . load ( ) ;
112103
113- // Used to test spawning a file data source from another file data source handler.
114- // This function spawns a file data source that will be handled by `handleSpawnedTest`.
115- export function spawnTestHandler ( data : Bytes ) : void {
116- let context = new DataSourceContext ( ) ;
117- context . setString ( "file" , "fromSpawnTestHandler" ) ;
118- let command = dataSource . context ( ) . getString ( "command" ) ;
119- if ( command == "spawnOffChainHandlerTest" ) {
120- dataSource . createWithContext ( "OffChainDataSource" , [ KNOWN_CID ] , context ) ;
121- } else if ( command == "spawnOnChainHandlerTest" ) {
122- dataSource . createWithContext ( "OnChainDataSource" , [ KNOWN_CID ] , context ) ;
104+ assert ( fileEntity . length == 0 , "Expected exactly one file entity" ) ;
105+ }
123106 }
124107}
125108
126- // This is the handler for the data source spawned by `spawnOffChainHandlerTest`.
127- export function handleSpawnedTest ( data : Bytes ) : void {
128- let entity = new SpawnTestEntity ( dataSource . stringParam ( ) ) ;
129- let context = dataSource . context ( ) . getString ( "file" ) ;
130- entity . content = data . toString ( ) ;
131- entity . context = context ;
132- entity . save ( ) ;
109+ export function handleFile ( data : Bytes ) : void {
110+ log . info ( "handleFile {}" , [ dataSource . stringParam ( ) ] ) ;
111+ let context = dataSource . context ( ) ;
112+
113+ if ( context . isSet ( "command" ) ) {
114+ let contextCommand = context . getString ( "command" ) ;
115+
116+ if ( contextCommand == SPAWN_FDS_FROM_OFFCHAIN_HANDLER ) {
117+ let hash = context . getString ( "hash" ) ;
118+ log . info ( "Creating file data source from handleFile: {}" , [ hash ] ) ;
119+ dataSource . createWithContext ( "File" , [ hash ] , new DataSourceContext ( ) ) ;
120+ }
121+
122+ if ( contextCommand == ONCHAIN_FROM_OFFCHAIN ) {
123+ log . info ( "Creating onchain data source from offchain handler" , [ ] ) ;
124+ let address = context . getString ( "address" ) ;
125+ dataSource . create ( "OnChainDataSource" , [ address ] ) ;
126+ }
127+
128+ if ( contextCommand == CREATE_UNDEFINED_ENTITY ) {
129+ log . info ( "Creating undefined entity" , [ ] ) ;
130+ let entity = new Foo ( dataSource . stringParam ( ) ) ;
131+ entity . save ( ) ;
132+ }
133+
134+ if ( contextCommand == CREATE_FOO ) {
135+ log . info ( "Creating FileEntity with relation to Foo" , [ ] ) ;
136+ let entity = new FileEntity ( dataSource . stringParam ( ) ) ;
137+ entity . foo = dataSource . stringParam ( ) ;
138+ entity . content = data . toString ( ) ;
139+ entity . save ( ) ;
140+ }
141+ } else {
142+ log . info ( "Creating FileEntity from handleFile: {} , content : {}" , [
143+ dataSource . stringParam ( ) ,
144+ data . toString ( ) ,
145+ ] ) ;
146+
147+ let entity = new FileEntity ( dataSource . stringParam ( ) ) ;
148+ entity . content = data . toString ( ) ;
149+ entity . save ( ) ;
150+ }
133151}
0 commit comments