graphprotocol / graph-tooling

Monorepo for various tools used by subgraph developers.
https://thegraph.com/docs
Apache License 2.0
389 stars 207 forks source link

Type `ethereum.TransactionReceipt | null` is not assignable to type `ethereum.TransactionReceipt` #1090

Open adamazad opened 2 years ago

adamazad commented 2 years ago

I have issues accessing event.receipt in a handler:

export function handleMint(event: Mint): void {

  if (event.receipt !== null) {
     // logic to handle receipt
  }

}
image

I added receipt: true per documentation. Definitely doesn't help.

      eventHandlers:
        - event: Mint(indexed address,uint256,uint256)
          handler: handleMint
          receipt: true

Full log:

yarn run v1.22.18
$ graph deploy adamazad/swapr-exp-one subgraph.xdai.yaml --ipfs https://api.thegraph.com/ipfs/ --node https://api.thegraph.com/deploy/ --debug
  Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2
  Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3
  Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4
  Skip migration: Bump mapping apiVersion from 0.0.4 to 0.0.5
  Skip migration: Bump mapping apiVersion from 0.0.5 to 0.0.6
  Skip migration: Bump manifest specVersion from 0.0.1 to 0.0.2
  Skip migration: Bump manifest specVersion from 0.0.2 to 0.0.4
✔ Apply migrations
✔ Load subgraph from subgraph.xdai.yaml
  Compile data source: Factory => build/Factory/Factory.wasm
  Compile data source: StakingRewardsFactory => build/StakingRewardsFactory/StakingRewardsFactory.wasm
  Compile data source template: Pair => build/templates/Pair/Pair.wasm
⠋ Compile subgraphERROR TS2322: Type '~lib/@graphprotocol/graph-ts/chain/ethereum/ethereum.TransactionReceipt | null' is not assignable to type '~lib/@graphprotocol/graph-ts/chain/ethereum/ethereum.TransactionReceipt'.

     event.receipt.logs.forEach((log) => {
     ~~~~~~~~~~~~~
 in src/mappings/core.ts(303,5)

✖ Failed to compile subgraph: Failed to compile data source template: 1 compile error(s)
Error: Failed to compile data source template: 1 compile error(s)
    at Compiler._compileTemplateMapping (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/@graphprotocol/graph-cli/src/compiler/index.js:374:13)
    at /Users/adam/workspace/dxdao/swapr-subgraph/node_modules/@graphprotocol/graph-cli/src/compiler/index.js:231:24
    at updateInDeepMap (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:1971:22)
    at updateInDeepMap (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:1980:23)
    at updateInDeepMap (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:1980:23)
    at Map.updateIn (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:1278:26)
    at /Users/adam/workspace/dxdao/swapr-subgraph/node_modules/@graphprotocol/graph-cli/src/compiler/index.js:230:26
    at /Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:3016:46
    at List.__iterate (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:2206:13)
    at IndexedIterable.mappedSequence.__iterateUncached (/Users/adam/workspace/dxdao/swapr-subgraph/node_modules/immutable/dist/immutable.js:3015:23)
UNCAUGHT EXCEPTION: Error: The AssemblyScript compiler crashed when compiling this file: 'src/mappings/core.ts'
Suggestion: try to comment the whole file and uncomment it little by little while re-running the graph-cli until you isolate the line where the problem happens.
Also, please contact us so we can make the CLI better by handling errors like this. You can reach out in any of these links:
- Discord channel: https://discord.gg/eM8CA6WA9r
- Github issues: https://github.com/graphprotocol/graph-cli/issues
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
leoyvens commented 2 years ago

Maybe you need to explicitly cast let receipt = event.receipt as TransactionReceipt

adamazad commented 2 years ago

Maybe you need to explicitly cast let receipt = event.receipt as TransactionReceipt

This worked! Can we document it in the docs please?

maoueh commented 2 years ago

This is a limitation of AssemblyScript compiler not understanding that you check the field in your if statement above. I different fix is to use ! suffix which tells AssemblyScript compiler: hey, I tell you that this field is 'non-null' so stop complaining.

export function handleMint(event: Mint): void {

  if (event.receipt !== null) {
     event.receipt!.logs.forEach(...)
  }

}

About the documentation issue, @azf20 how can we improve the situation? Feels like an AssemblyScript gotchas to me, so I'm unsure where it could be put.

azf20 commented 2 years ago

This is a good question, and quite relevant to the AssemblyScript guide we have previously discussed adding to our docs with @schmidsi .. I wonder if an FAQ with that kind of info (common issues) would be helpful here https://thegraph.com/docs/en/developing/assemblyscript-api/ 🤔

0xdavinchee commented 2 years ago

Hello, I am actually having this issue even though I am doing the casting as you mentioned @leoyvens. You can see the attempt here. I've pasted the error I am receiving here.

I have bumped the graph-cli, graph-ts versions and I am getting this error:

graph-node_1  | Oct 17 13:16:12.886 ERRO Subgraph instance failed to run: Tried to read AssemblyScript value that is 'null'. Suggestion: look into the function that the error happened and add 'log' calls till you find where a 'null' value is being used as non-nullable. It's likely that you're calling a 'graph-ts' function (or operator) with a 'null' value when it doesn't support it.   wasm backtrace:     0: 0x3759 - <unknown>!src/mappings/host/handleAgreementClassUpdated  in handler `handleAgreementClassRegistered` at block graphprotocol/graph-ts#4 (4c1316bccd765376b914a522af47ff136a54a32298caba7b6d197aff69d929d2), code: SubgraphSyncingFailure, sgd: 1, subgraph_id: QmRKKKFKan7RuxSvCP5wAgFcTfkhN3GQWd8Ac2HZrD5dbP, component: SubgraphInstanceManager
maoueh commented 2 years ago

@0xdavinchee If you see the error in graph-node itself, it means it's a runtime time error, you told the compiler that the value would never be null, but it's not the case, you are having a null value and the runtime fails because you are trying to read a null value.

The casting trick or the enforce non-null trick needs to be used if you are 100% sure that the value will not be null and you help the compiler understand that fact. If you lie to the compiler and the value is actually null at some point, you get a runtime error just like you see above.

Maybe the ethereum.TransactionReceipt is indeed null because maybe the apiVersion/specVersion was not specified correctly? I'm not familiar with the whereabouts of TransactionReceipt on the event sadly.

0xdavinchee commented 2 years ago

hi @maoueh I am pretty sure the specVersion and apiVersion are set correctly: see here the specified specVersion and apiVersion should be 0.0.5 and 0.0.7, respectively.

Also wanted to note that this is happening in a local testing environment with graph-node running in docker.

azf20 commented 2 years ago

hey @0xdavinchee does this fail on the first event? (i.e. there are no successes)

0xdavinchee commented 2 years ago

hey @0xdavinchee does this fail on the first event? (i.e. there are no successes)

Yes it does, no successes

dimitrovmaksim commented 2 years ago

Don't use === or !== in AssemblyScrip prior to v0.20.0 (TheGraph uses 0.19.x), it is used for identity comparison (e.g. the values are the same object) not value equality, that has been changed in AS v0.20.0 i think to work similarly to == and != https://github.com/AssemblyScript/assemblyscript/issues/621#issuecomment-497973428

Also for nullability checks you have to assign the receipt to a variable: https://www.assemblyscript.org/concepts.html

let receipt = log.receipt
if (receipt) {
     // logic to handle receipt
 }
0xdavinchee commented 1 year ago

NOTE: I am doing the following existence check:

if (event.receipt) {
   doSomething(event.receipt.gasUsed);
}

I've been able to get this to work, however the compiler still requires me to cast:

const receipt = event.receipt as ethereum.TransactionReceipt;

If I don't do this I get this error:

FAILURE 1 compile error(s)
ERROR TS2322: Type '~lib/@graphprotocol/graph-ts/chain/ethereum/ethereum.TransactionReceipt | null' is not assignable to type '~lib/@graphprotocol/graph-ts/chain/ethereum/ethereum.TransactionReceipt'.

Not a big deal, but I don't think this is the desired behavior.

maoueh commented 1 year ago

@0xdavinchee It's a limitation of the AssemblyScript compiler as it does not correctly make the analysis that event.receipt is non-null within the if statement when used directly. Reading AssemblyScript doc lead me to learn that if you assign to a variable first, the compiler is able to make the analysis:

const receipt = event.receipt;
if (receipt) {
   // Compiler knowns correctly now that `receipt` variable is not `null`
   doSomething(receipt.gasUsed);
}

Another way without the variable or the type cast like you did:

if (event.receipt) {
   // Compiler knowns correctly now that `event.receipt` variable is not `null` because its access is suffixed with `!`
   doSomething(event.receipt!.gasUsed);
}

See https://www.assemblyscript.org/concepts.html#strictly-typed and look for And nullability checks are limited to locals to guarantee soundness where TypeScript would not diagnose a problem.

Nothing we can really do on the graph side outside of better documenting those behavior.

0xdavinchee commented 1 year ago

@0xdavinchee It's a limitation of the AssemblyScript compiler as it does not correctly make the analysis that event.receipt is non-null within the if statement when used directly. Reading AssemblyScript doc lead me to learn that if you assign to a variable first, the compiler is able to make the analysis:

const receipt = event.receipt;
if (receipt) {
   // Compiler knowns correctly now that `receipt` variable is not `null`
   doSomething(receipt.gasUsed);
}

Another way without the variable or the type cast like you did:

if (event.receipt) {
   // Compiler knowns correctly now that `event.receipt` variable is not `null` because its access is suffixed with `!`
   doSomething(event.receipt!.gasUsed);
}

See https://www.assemblyscript.org/concepts.html#strictly-typed and look for And nullability checks are limited to locals to guarantee soundness where TypeScript would not diagnose a problem.

Nothing we can really do on the graph side outside of better documenting those behavior.

Gotcha, thank you for letting me know, just wanted to bring this to your attention. Appreciate the good stuff you guys are doing there at edge and node! 🙏

maoueh commented 1 year ago

Thanks, I'm at StreamingFast though, hopefully you like what we do also ;P