Neo: Storage.CurrentContext as static variable leads to error when contract's verify method is called

Created on 2 Mar 2021  路  3Comments  路  Source: neo-project/neo

Describe the bug

When I use the Storage.CurrentContext for a static field variable in a smart contract I cannot successfully call the calculatenetworkfee RPC method with a transaction that withdraws tokens from that contract.

To Reproduce

  1. Run a Neo network based on the Neo3-preview5 release.
  2. Create, compile, and deploy a simple dummy smart contract like the following one:
class DotnetContract : SmartContract
{
    private static StorageContext sc = Storage.CurrentContext;

    public static bool verify() {
        return true;
    }

    public static void onNEP17Payment(UInt160 from, int amount, object data) {
        return;
    }
}
  1. Send some GAS to the contract's address.
  2. Create a transaction withdrawing GAS from the contract (make sure to attach the correct witnesses).
  3. Send the transaction hex with the calculatenetworkfee RPC method to a neo-node in your network.
  4. Should return the following error: "Smart contract {contract.Hash} verification fault."

Do the same but without the static StorageContext variable. Then it should work.

Expected behavior

Calling the calculatenetworkfee method with a transaction that withdraws tokens from a contract successfully calls the verify method and ends in VM state HALT even if the contract uses Storage.CurrentContext for a static field variable.

Most helpful comment

Looks like this to me:

--- a/src/neo/Wallets/Wallet.cs
+++ b/src/neo/Wallets/Wallet.cs
@@ -398,7 +398,7 @@ namespace Neo.Wallets

                     // Check verify cost
                     using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot());
-                    engine.LoadContract(contract, md, CallFlags.None);
+                    engine.LoadContract(contract, md, CallFlags.ReadOnly);
                     if (NativeContract.IsNative(hash)) engine.Push("verify");
                     if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.Hash} verification fault.");
                     if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false.");

All 3 comments

It would be cool if someone could take a look at this asap since it's affecting the functionality of "withdrawing assets from smart contracts" in neow3j, as well as some tests.

Looks like this to me:

--- a/src/neo/Wallets/Wallet.cs
+++ b/src/neo/Wallets/Wallet.cs
@@ -398,7 +398,7 @@ namespace Neo.Wallets

                     // Check verify cost
                     using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot());
-                    engine.LoadContract(contract, md, CallFlags.None);
+                    engine.LoadContract(contract, md, CallFlags.ReadOnly);
                     if (NativeContract.IsNative(hash)) engine.Push("verify");
                     if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.Hash} verification fault.");
                     if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false.");

It is because syscall of GetStorage require Read callFlags, so it failed when call with CallFlags.None.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

doubiliu picture doubiliu  路  3Comments

realloc picture realloc  路  4Comments

shargon picture shargon  路  4Comments

igormcoelho picture igormcoelho  路  4Comments

borovik96 picture borovik96  路  4Comments