Using opcode `LDSFLD0` instead of `LDSFLD 00` leads to unexpected return type.
Closed this issue ยท 6 comments
The following (meaningless) contract produces the script below when compiled with neon (version neo3-preview3).
public class Contract : SmartContract
{
static byte[] owner = "AJunErzotcQTNWP2qktA7LgkXZVdHea97H".ToScriptHash();
public static bool main()
{
if(!Runtime.CheckWitness(owner)) {
return false;
}
return true;
}
}
LDSFLD 00
SYSCALL f827ec8c
JMPIF_L 07000000
PUSH0
RET
PUSH1
RET
INITSSLOT 01
PUSHDATA1 20 226730eaeec8e3315468f57153e3b08789cc45cc
STSFLD0
RET
And this is the same script as a hex string: 215f002141f827ec8c25070000001040114056010c14226730eaeec8e3315468f57153e3b08789cc45cc6040
Our neow3j compiler produces a same script with the only difference that the LDSFLD 00
instruction is replaced with LDSFLD0
.
This is a valid instruction and as far as i know, does the same as LDSFLD 00
.
But when the script using LDSFLD0
is executed - the only method on the contract is called - the returned value is null
and the StackItemType is ANY
.
Once we replace the instruction LDSFLD0
with LDSFLD 00
, the returned value is as expected, i.e. 1 or 0 depending if the transaction signer is the contract owner.
Having LDSFLD0
in the above script instead of LDSFLD 00
should not make any difference.
We will improve this compilation (neo-project/neo-devpack-dotnet#382), but the logic for LDSFLD 00
and LDSFLD0
it's the same
neo-vm/src/neo-vm/ExecutionEngine.cs
Lines 505 to 512 in a14b934
I have tested it on neo3-preview3 testnet, both contracts return the same result:
neo> invoke 0xca42bd2e02e9b680b44cf7fd2badb02beaa14092 main []
Invoking script with: '10c00c046d61696e0c149240a1ea2bb0ad2bfdf74cb480b6e9022ebd42ca41627d5b52'
VM State: HALT
Gas Consumed: 0.0103953
Result Stack: [{"type":"Integer","value":"0"}]
Relay tx(no|yes): no
neo> invoke 0x1e394dd787a02b95482304c387a88b055c972b5d main []
Invoking script with: '10c00c046d61696e0c145d2b975c058ba887c3042348952ba087d74d391e41627d5b52'
VM State: HALT
Gas Consumed: 0.0103956
Result Stack: [{"type":"Integer","value":"0"}]
Relay tx(no|yes):
You can getcontractstate
and check my contracts.
0xca42bd2e02e9b680b44cf7fd2badb02beaa14092
, the hex string is 5702005f0041f827ec8c10b370682606107122041171694056010c14f4e43bf177ad38113b29524cace20cbed17951b96040
0x1e394dd787a02b95482304c387a88b055c972b5d
, the hex string is 570200582141f827ec8c10b370682606107122041171694056010c14f4e43bf177ad38113b29524cace20cbed17951b96040
The only difference is that 5f00
and 5821
.
Hey @ProDog, @shargon, @Tommo-L, Thanks a lot for looking into it.
I was mistaken about this issue. Neo-vm is not at fault. The problem was that the contract manifests that i produced (from Java contracts) had wrong method offsets when using the ToScriptHash()
๐ The offset would sometimes point outside of the script's bounds leading to weird behavior.
Thus, this issue can be closed.
But, one question remains. Shouldn't the neo-vm exit in state FAULT when the method offset points to an address outside of the script's bounds? Should I create an issue for this behavior?
Hey @ProDog, @shargon, @Tommo-L, Thanks a lot for looking into it.
I was mistaken about this issue. Neo-vm is not at fault. The problem was that the contract manifests that i produced (from Java contracts) had wrong method offsets when using the ToScriptHash() ๐ The offset would sometimes point outside of the script's bounds leading to weird behavior.
Thus, this issue can be closed.
This will be solved with neo-project/neo-devpack-dotnet#382
But, one question remains. Shouldn't the neo-vm exit in state FAULT when the method offset points to an address outside of the script's bounds? Should I create an issue for this behavior?
You can open a issue, at now it's the same as RET