Implemented most of the stubbed-out state handling instructions (#59)
Merge note: currently cannot compile due to `quasiBoolean` (#63). This will be solved by https://github.com/status-im/nimbus/pull/65 ---- * Implemented most of the stubbed out state handling instructions The code compiles, but still fails at the moment due to incorrect initialization of the VM. Don't merge yet. More commits will be pushed in the coming days. * Fixed crash * trie put and del are void now * getBlockTransactionData and getReceipts * Working code for extcodesize0.json * fix origin.json * fix calldatasize1 * fix calldataloadSizeTooHighPartial * fix calldataloadSizeTooHigh * more efficient PushX implementation * fix and, or, xor
This commit is contained in:
parent
6f28d11866
commit
18b7bbb3b0
184
VMTests.md
184
VMTests.md
|
@ -115,7 +115,7 @@ VMTests
|
||||||
+ expPowerOf2_4.json OK
|
+ expPowerOf2_4.json OK
|
||||||
+ expPowerOf2_64.json OK
|
+ expPowerOf2_64.json OK
|
||||||
+ expPowerOf2_8.json OK
|
+ expPowerOf2_8.json OK
|
||||||
- expXY.json Fail
|
+ expXY.json OK
|
||||||
+ expXY_success.json OK
|
+ expXY_success.json OK
|
||||||
+ fibbonacci_unrolled.json OK
|
+ fibbonacci_unrolled.json OK
|
||||||
+ mod0.json OK
|
+ mod0.json OK
|
||||||
|
@ -150,12 +150,12 @@ VMTests
|
||||||
+ mulmoddivByZero2.json OK
|
+ mulmoddivByZero2.json OK
|
||||||
+ mulmoddivByZero3.json OK
|
+ mulmoddivByZero3.json OK
|
||||||
+ not1.json OK
|
+ not1.json OK
|
||||||
+ sdiv0.json OK
|
- sdiv0.json Fail
|
||||||
+ sdiv1.json OK
|
+ sdiv1.json OK
|
||||||
+ sdiv2.json OK
|
+ sdiv2.json OK
|
||||||
+ sdiv3.json OK
|
- sdiv3.json Fail
|
||||||
+ sdiv4.json OK
|
- sdiv4.json Fail
|
||||||
+ sdiv5.json OK
|
- sdiv5.json Fail
|
||||||
+ sdiv6.json OK
|
+ sdiv6.json OK
|
||||||
+ sdiv7.json OK
|
+ sdiv7.json OK
|
||||||
+ sdiv8.json OK
|
+ sdiv8.json OK
|
||||||
|
@ -164,8 +164,8 @@ VMTests
|
||||||
+ sdivByZero1.json OK
|
+ sdivByZero1.json OK
|
||||||
+ sdivByZero2.json OK
|
+ sdivByZero2.json OK
|
||||||
+ sdiv_dejavu.json OK
|
+ sdiv_dejavu.json OK
|
||||||
+ sdiv_i256min.json OK
|
- sdiv_i256min.json Fail
|
||||||
+ sdiv_i256min2.json OK
|
- sdiv_i256min2.json Fail
|
||||||
+ sdiv_i256min3.json OK
|
+ sdiv_i256min3.json OK
|
||||||
+ signextendInvalidByteNumber.json OK
|
+ signextendInvalidByteNumber.json OK
|
||||||
+ signextend_00.json OK
|
+ signextend_00.json OK
|
||||||
|
@ -180,9 +180,9 @@ VMTests
|
||||||
+ signextend_Overflow_dj42.json OK
|
+ signextend_Overflow_dj42.json OK
|
||||||
+ signextend_bigBytePlus1.json OK
|
+ signextend_bigBytePlus1.json OK
|
||||||
+ signextend_bitIsSet.json OK
|
+ signextend_bitIsSet.json OK
|
||||||
+ smod0.json OK
|
- smod0.json Fail
|
||||||
+ smod1.json OK
|
- smod1.json Fail
|
||||||
+ smod2.json OK
|
- smod2.json Fail
|
||||||
+ smod3.json OK
|
+ smod3.json OK
|
||||||
+ smod4.json OK
|
+ smod4.json OK
|
||||||
+ smod5.json OK
|
+ smod5.json OK
|
||||||
|
@ -190,7 +190,7 @@ VMTests
|
||||||
+ smod7.json OK
|
+ smod7.json OK
|
||||||
+ smod8_byZero.json OK
|
+ smod8_byZero.json OK
|
||||||
+ smod_i256min1.json OK
|
+ smod_i256min1.json OK
|
||||||
+ smod_i256min2.json OK
|
- smod_i256min2.json Fail
|
||||||
+ stop.json OK
|
+ stop.json OK
|
||||||
+ sub0.json OK
|
+ sub0.json OK
|
||||||
+ sub1.json OK
|
+ sub1.json OK
|
||||||
|
@ -198,7 +198,7 @@ VMTests
|
||||||
+ sub3.json OK
|
+ sub3.json OK
|
||||||
+ sub4.json OK
|
+ sub4.json OK
|
||||||
```
|
```
|
||||||
OK: 194/195 Fail: 1/195 Skip: 0/195
|
OK: 185/195 Fail: 10/195 Skip: 0/195
|
||||||
## vmBitwiseLogicOperation
|
## vmBitwiseLogicOperation
|
||||||
```diff
|
```diff
|
||||||
+ and0.json OK
|
+ and0.json OK
|
||||||
|
@ -267,7 +267,7 @@ OK: 60/60 Fail: 0/60 Skip: 0/60
|
||||||
```diff
|
```diff
|
||||||
+ blockhash257Block.json OK
|
+ blockhash257Block.json OK
|
||||||
+ blockhash258Block.json OK
|
+ blockhash258Block.json OK
|
||||||
+ blockhashInRange.json OK
|
- blockhashInRange.json Fail
|
||||||
+ blockhashMyBlock.json OK
|
+ blockhashMyBlock.json OK
|
||||||
+ blockhashNotExistingBlock.json OK
|
+ blockhashNotExistingBlock.json OK
|
||||||
+ blockhashOutOfRange.json OK
|
+ blockhashOutOfRange.json OK
|
||||||
|
@ -278,21 +278,21 @@ OK: 60/60 Fail: 0/60 Skip: 0/60
|
||||||
+ number.json OK
|
+ number.json OK
|
||||||
+ timestamp.json OK
|
+ timestamp.json OK
|
||||||
```
|
```
|
||||||
OK: 12/12 Fail: 0/12 Skip: 0/12
|
OK: 11/12 Fail: 1/12 Skip: 0/12
|
||||||
## vmEnvironmentalInfo
|
## vmEnvironmentalInfo
|
||||||
```diff
|
```diff
|
||||||
ExtCodeSizeAddressInputTooBigLeftMyAddress.json Skip
|
+ ExtCodeSizeAddressInputTooBigLeftMyAddress.json OK
|
||||||
ExtCodeSizeAddressInputTooBigRightMyAddress.json Skip
|
+ ExtCodeSizeAddressInputTooBigRightMyAddress.json OK
|
||||||
address0.json Skip
|
+ address0.json OK
|
||||||
address1.json Skip
|
+ address1.json OK
|
||||||
balance0.json Skip
|
+ balance0.json OK
|
||||||
balance01.json Skip
|
- balance01.json Fail
|
||||||
balance1.json Skip
|
- balance1.json Fail
|
||||||
balanceAddress2.json Skip
|
+ balanceAddress2.json OK
|
||||||
balanceAddressInputTooBig.json Skip
|
+ balanceAddressInputTooBig.json OK
|
||||||
balanceAddressInputTooBigLeftMyAddress.json Skip
|
- balanceAddressInputTooBigLeftMyAddress.json Fail
|
||||||
balanceAddressInputTooBigRightMyAddress.json Skip
|
balanceAddressInputTooBigRightMyAddress.json Skip
|
||||||
balanceCaller3.json Skip
|
+ balanceCaller3.json OK
|
||||||
calldatacopy0.json Skip
|
calldatacopy0.json Skip
|
||||||
calldatacopy0_return.json Skip
|
calldatacopy0_return.json Skip
|
||||||
calldatacopy1.json Skip
|
calldatacopy1.json Skip
|
||||||
|
@ -307,41 +307,41 @@ OK: 12/12 Fail: 0/12 Skip: 0/12
|
||||||
calldatacopy_DataIndexTooHigh2_return.json Skip
|
calldatacopy_DataIndexTooHigh2_return.json Skip
|
||||||
calldatacopy_DataIndexTooHigh_return.json Skip
|
calldatacopy_DataIndexTooHigh_return.json Skip
|
||||||
calldatacopy_sec.json Skip
|
calldatacopy_sec.json Skip
|
||||||
calldataload0.json Skip
|
+ calldataload0.json OK
|
||||||
calldataload1.json Skip
|
+ calldataload1.json OK
|
||||||
calldataload2.json Skip
|
+ calldataload2.json OK
|
||||||
calldataloadSizeTooHigh.json Skip
|
+ calldataloadSizeTooHigh.json OK
|
||||||
calldataloadSizeTooHighPartial.json Skip
|
+ calldataloadSizeTooHighPartial.json OK
|
||||||
calldataload_BigOffset.json Skip
|
+ calldataload_BigOffset.json OK
|
||||||
calldatasize0.json Skip
|
+ calldatasize0.json OK
|
||||||
calldatasize1.json Skip
|
+ calldatasize1.json OK
|
||||||
calldatasize2.json Skip
|
+ calldatasize2.json OK
|
||||||
caller.json Skip
|
+ caller.json OK
|
||||||
callvalue.json Skip
|
+ callvalue.json OK
|
||||||
codecopy0.json Skip
|
- codecopy0.json Fail
|
||||||
codecopyZeroMemExpansion.json Skip
|
+ codecopyZeroMemExpansion.json OK
|
||||||
codecopy_DataIndexTooHigh.json Skip
|
- codecopy_DataIndexTooHigh.json Fail
|
||||||
codesize.json Skip
|
+ codesize.json OK
|
||||||
env1.json Skip
|
- env1.json Fail
|
||||||
extcodecopy0.json Skip
|
- extcodecopy0.json Fail
|
||||||
extcodecopy0AddressTooBigLeft.json Skip
|
- extcodecopy0AddressTooBigLeft.json Fail
|
||||||
extcodecopy0AddressTooBigRight.json Skip
|
- extcodecopy0AddressTooBigRight.json Fail
|
||||||
extcodecopyZeroMemExpansion.json Skip
|
- extcodecopyZeroMemExpansion.json Fail
|
||||||
extcodecopy_DataIndexTooHigh.json Skip
|
- extcodecopy_DataIndexTooHigh.json Fail
|
||||||
extcodesize0.json Skip
|
+ extcodesize0.json OK
|
||||||
extcodesize1.json Skip
|
+ extcodesize1.json OK
|
||||||
extcodesizeUnderFlow.json Skip
|
+ extcodesizeUnderFlow.json OK
|
||||||
gasprice.json Skip
|
+ gasprice.json OK
|
||||||
origin.json Skip
|
+ origin.json OK
|
||||||
```
|
```
|
||||||
OK: 0/52 Fail: 0/52 Skip: 52/52
|
OK: 26/52 Fail: 11/52 Skip: 15/52
|
||||||
## vmIOandFlowOperations
|
## vmIOandFlowOperations
|
||||||
```diff
|
```diff
|
||||||
+ BlockNumberDynamicJump0_AfterJumpdest.json OK
|
+ BlockNumberDynamicJump0_AfterJumpdest.json OK
|
||||||
+ BlockNumberDynamicJump0_AfterJumpdest3.json OK
|
+ BlockNumberDynamicJump0_AfterJumpdest3.json OK
|
||||||
+ BlockNumberDynamicJump0_foreverOutOfGas.json OK
|
+ BlockNumberDynamicJump0_foreverOutOfGas.json OK
|
||||||
- BlockNumberDynamicJump0_jumpdest0.json Fail
|
+ BlockNumberDynamicJump0_jumpdest0.json OK
|
||||||
- BlockNumberDynamicJump0_jumpdest2.json Fail
|
+ BlockNumberDynamicJump0_jumpdest2.json OK
|
||||||
+ BlockNumberDynamicJump0_withoutJumpdest.json OK
|
+ BlockNumberDynamicJump0_withoutJumpdest.json OK
|
||||||
+ BlockNumberDynamicJump1.json OK
|
+ BlockNumberDynamicJump1.json OK
|
||||||
+ BlockNumberDynamicJumpInsidePushWithJumpDest.json OK
|
+ BlockNumberDynamicJumpInsidePushWithJumpDest.json OK
|
||||||
|
@ -353,7 +353,7 @@ OK: 0/52 Fail: 0/52 Skip: 52/52
|
||||||
- BlockNumberDynamicJumpiOutsideBoundary.json Fail
|
- BlockNumberDynamicJumpiOutsideBoundary.json Fail
|
||||||
+ BlockNumberDynamicJumpifInsidePushWithJumpDest.json OK
|
+ BlockNumberDynamicJumpifInsidePushWithJumpDest.json OK
|
||||||
+ BlockNumberDynamicJumpifInsidePushWithoutJumpDest.json OK
|
+ BlockNumberDynamicJumpifInsidePushWithoutJumpDest.json OK
|
||||||
- DyanmicJump0_outOfBoundary.json Fail
|
+ DyanmicJump0_outOfBoundary.json OK
|
||||||
+ DynamicJump0_AfterJumpdest.json OK
|
+ DynamicJump0_AfterJumpdest.json OK
|
||||||
+ DynamicJump0_AfterJumpdest3.json OK
|
+ DynamicJump0_AfterJumpdest3.json OK
|
||||||
+ DynamicJump0_foreverOutOfGas.json OK
|
+ DynamicJump0_foreverOutOfGas.json OK
|
||||||
|
@ -366,15 +366,15 @@ OK: 0/52 Fail: 0/52 Skip: 52/52
|
||||||
+ DynamicJumpInsidePushWithoutJumpDest.json OK
|
+ DynamicJumpInsidePushWithoutJumpDest.json OK
|
||||||
+ DynamicJumpJD_DependsOnJumps0.json OK
|
+ DynamicJumpJD_DependsOnJumps0.json OK
|
||||||
+ DynamicJumpJD_DependsOnJumps1.json OK
|
+ DynamicJumpJD_DependsOnJumps1.json OK
|
||||||
- DynamicJumpPathologicalTest0.json Fail
|
+ DynamicJumpPathologicalTest0.json OK
|
||||||
+ DynamicJumpPathologicalTest1.json OK
|
+ DynamicJumpPathologicalTest1.json OK
|
||||||
+ DynamicJumpPathologicalTest2.json OK
|
+ DynamicJumpPathologicalTest2.json OK
|
||||||
+ DynamicJumpPathologicalTest3.json OK
|
+ DynamicJumpPathologicalTest3.json OK
|
||||||
+ DynamicJumpStartWithJumpDest.json OK
|
+ DynamicJumpStartWithJumpDest.json OK
|
||||||
+ DynamicJump_value1.json OK
|
- DynamicJump_value1.json Fail
|
||||||
+ DynamicJump_value2.json OK
|
- DynamicJump_value2.json Fail
|
||||||
+ DynamicJump_value3.json OK
|
- DynamicJump_value3.json Fail
|
||||||
+ DynamicJump_valueUnderflow.json OK
|
- DynamicJump_valueUnderflow.json Fail
|
||||||
+ DynamicJumpi0.json OK
|
+ DynamicJumpi0.json OK
|
||||||
+ DynamicJumpi1.json OK
|
+ DynamicJumpi1.json OK
|
||||||
+ DynamicJumpi1_jumpdest.json OK
|
+ DynamicJumpi1_jumpdest.json OK
|
||||||
|
@ -382,22 +382,22 @@ OK: 0/52 Fail: 0/52 Skip: 52/52
|
||||||
- DynamicJumpiOutsideBoundary.json Fail
|
- DynamicJumpiOutsideBoundary.json Fail
|
||||||
+ DynamicJumpifInsidePushWithJumpDest.json OK
|
+ DynamicJumpifInsidePushWithJumpDest.json OK
|
||||||
+ DynamicJumpifInsidePushWithoutJumpDest.json OK
|
+ DynamicJumpifInsidePushWithoutJumpDest.json OK
|
||||||
- JDfromStorageDynamicJump0_AfterJumpdest.json Fail
|
+ JDfromStorageDynamicJump0_AfterJumpdest.json OK
|
||||||
- JDfromStorageDynamicJump0_AfterJumpdest3.json Fail
|
+ JDfromStorageDynamicJump0_AfterJumpdest3.json OK
|
||||||
- JDfromStorageDynamicJump0_foreverOutOfGas.json Fail
|
+ JDfromStorageDynamicJump0_foreverOutOfGas.json OK
|
||||||
- JDfromStorageDynamicJump0_jumpdest0.json Fail
|
- JDfromStorageDynamicJump0_jumpdest0.json Fail
|
||||||
- JDfromStorageDynamicJump0_jumpdest2.json Fail
|
- JDfromStorageDynamicJump0_jumpdest2.json Fail
|
||||||
- JDfromStorageDynamicJump0_withoutJumpdest.json Fail
|
+ JDfromStorageDynamicJump0_withoutJumpdest.json OK
|
||||||
- JDfromStorageDynamicJump1.json Fail
|
+ JDfromStorageDynamicJump1.json OK
|
||||||
- JDfromStorageDynamicJumpInsidePushWithJumpDest.json Fail
|
+ JDfromStorageDynamicJumpInsidePushWithJumpDest.json OK
|
||||||
- JDfromStorageDynamicJumpInsidePushWithoutJumpDest.json Fail
|
+ JDfromStorageDynamicJumpInsidePushWithoutJumpDest.json OK
|
||||||
- JDfromStorageDynamicJumpi0.json Fail
|
+ JDfromStorageDynamicJumpi0.json OK
|
||||||
- JDfromStorageDynamicJumpi1.json Fail
|
- JDfromStorageDynamicJumpi1.json Fail
|
||||||
- JDfromStorageDynamicJumpi1_jumpdest.json Fail
|
+ JDfromStorageDynamicJumpi1_jumpdest.json OK
|
||||||
- JDfromStorageDynamicJumpiAfterStop.json Fail
|
- JDfromStorageDynamicJumpiAfterStop.json Fail
|
||||||
- JDfromStorageDynamicJumpiOutsideBoundary.json Fail
|
+ JDfromStorageDynamicJumpiOutsideBoundary.json OK
|
||||||
- JDfromStorageDynamicJumpifInsidePushWithJumpDest.json Fail
|
+ JDfromStorageDynamicJumpifInsidePushWithJumpDest.json OK
|
||||||
- JDfromStorageDynamicJumpifInsidePushWithoutJumpDest.json Fail
|
+ JDfromStorageDynamicJumpifInsidePushWithoutJumpDest.json OK
|
||||||
+ bad_indirect_jump1.json OK
|
+ bad_indirect_jump1.json OK
|
||||||
+ bad_indirect_jump2.json OK
|
+ bad_indirect_jump2.json OK
|
||||||
+ byte1.json OK
|
+ byte1.json OK
|
||||||
|
@ -461,9 +461,9 @@ OK: 0/52 Fail: 0/52 Skip: 52/52
|
||||||
+ mstore0.json OK
|
+ mstore0.json OK
|
||||||
+ mstore1.json OK
|
+ mstore1.json OK
|
||||||
+ mstore8MemExp.json OK
|
+ mstore8MemExp.json OK
|
||||||
+ mstore8WordToBigError.json OK
|
- mstore8WordToBigError.json Fail
|
||||||
+ mstore8_0.json OK
|
- mstore8_0.json Fail
|
||||||
+ mstore8_1.json OK
|
- mstore8_1.json Fail
|
||||||
+ mstoreMemExp.json OK
|
+ mstoreMemExp.json OK
|
||||||
+ mstoreWordToBigError.json OK
|
+ mstoreWordToBigError.json OK
|
||||||
+ mstore_mload0.json OK
|
+ mstore_mload0.json OK
|
||||||
|
@ -475,15 +475,15 @@ OK: 0/52 Fail: 0/52 Skip: 52/52
|
||||||
- return2.json Fail
|
- return2.json Fail
|
||||||
+ sha3MemExp.json OK
|
+ sha3MemExp.json OK
|
||||||
+ sstore_load_0.json OK
|
+ sstore_load_0.json OK
|
||||||
+ sstore_load_1.json OK
|
- sstore_load_1.json Fail
|
||||||
- sstore_load_2.json Fail
|
- sstore_load_2.json Fail
|
||||||
+ sstore_underflow.json OK
|
+ sstore_underflow.json OK
|
||||||
+ stack_loop.json OK
|
- stack_loop.json Fail
|
||||||
+ stackjump1.json OK
|
+ stackjump1.json OK
|
||||||
+ swapAt52becameMstore.json OK
|
+ swapAt52becameMstore.json OK
|
||||||
+ when.json OK
|
+ when.json OK
|
||||||
```
|
```
|
||||||
OK: 103/145 Fail: 41/145 Skip: 1/145
|
OK: 110/145 Fail: 34/145 Skip: 1/145
|
||||||
## vmLogTest
|
## vmLogTest
|
||||||
```diff
|
```diff
|
||||||
+ log0_emptyMem.json OK
|
+ log0_emptyMem.json OK
|
||||||
|
@ -614,7 +614,7 @@ OK: 0/18 Fail: 0/18 Skip: 18/18
|
||||||
+ push7.json OK
|
+ push7.json OK
|
||||||
+ push8.json OK
|
+ push8.json OK
|
||||||
+ push9.json OK
|
+ push9.json OK
|
||||||
+ swap1.json OK
|
- swap1.json Fail
|
||||||
+ swap10.json OK
|
+ swap10.json OK
|
||||||
+ swap11.json OK
|
+ swap11.json OK
|
||||||
+ swap12.json OK
|
+ swap12.json OK
|
||||||
|
@ -631,9 +631,9 @@ OK: 0/18 Fail: 0/18 Skip: 18/18
|
||||||
+ swap7.json OK
|
+ swap7.json OK
|
||||||
+ swap8.json OK
|
+ swap8.json OK
|
||||||
+ swap9.json OK
|
+ swap9.json OK
|
||||||
+ swapjump1.json OK
|
- swapjump1.json Fail
|
||||||
```
|
```
|
||||||
OK: 74/74 Fail: 0/74 Skip: 0/74
|
OK: 72/74 Fail: 2/74 Skip: 0/74
|
||||||
## vmRandomTest
|
## vmRandomTest
|
||||||
```diff
|
```diff
|
||||||
201503102037PYTHON.json Skip
|
201503102037PYTHON.json Skip
|
||||||
|
@ -658,25 +658,25 @@ OK: 0/17 Fail: 0/17 Skip: 17/17
|
||||||
## vmSha3Test
|
## vmSha3Test
|
||||||
```diff
|
```diff
|
||||||
+ sha3_0.json OK
|
+ sha3_0.json OK
|
||||||
+ sha3_1.json OK
|
- sha3_1.json Fail
|
||||||
+ sha3_2.json OK
|
- sha3_2.json Fail
|
||||||
+ sha3_3.json OK
|
+ sha3_3.json OK
|
||||||
+ sha3_4.json OK
|
+ sha3_4.json OK
|
||||||
+ sha3_5.json OK
|
+ sha3_5.json OK
|
||||||
- sha3_6.json Fail
|
- sha3_6.json Fail
|
||||||
- sha3_bigOffset.json Fail
|
- sha3_bigOffset.json Fail
|
||||||
+ sha3_bigOffset2.json OK
|
- sha3_bigOffset2.json Fail
|
||||||
- sha3_bigSize.json Fail
|
- sha3_bigSize.json Fail
|
||||||
+ sha3_memSizeNoQuadraticCost31.json OK
|
- sha3_memSizeNoQuadraticCost31.json Fail
|
||||||
+ sha3_memSizeQuadraticCost32.json OK
|
- sha3_memSizeQuadraticCost32.json Fail
|
||||||
- sha3_memSizeQuadraticCost32_zeroSize.json Fail
|
- sha3_memSizeQuadraticCost32_zeroSize.json Fail
|
||||||
+ sha3_memSizeQuadraticCost33.json OK
|
- sha3_memSizeQuadraticCost33.json Fail
|
||||||
+ sha3_memSizeQuadraticCost63.json OK
|
- sha3_memSizeQuadraticCost63.json Fail
|
||||||
+ sha3_memSizeQuadraticCost64.json OK
|
- sha3_memSizeQuadraticCost64.json Fail
|
||||||
+ sha3_memSizeQuadraticCost64_2.json OK
|
- sha3_memSizeQuadraticCost64_2.json Fail
|
||||||
+ sha3_memSizeQuadraticCost65.json OK
|
- sha3_memSizeQuadraticCost65.json Fail
|
||||||
```
|
```
|
||||||
OK: 14/18 Fail: 4/18 Skip: 0/18
|
OK: 4/18 Fail: 14/18 Skip: 0/18
|
||||||
## vmSystemOperations
|
## vmSystemOperations
|
||||||
```diff
|
```diff
|
||||||
ABAcalls0.json Skip
|
ABAcalls0.json Skip
|
||||||
|
|
|
@ -6,16 +6,18 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
constants, errors, stint, rlp, eth_common
|
constants, errors, eth_common, rlp, eth_common/eth_types
|
||||||
|
|
||||||
type
|
type
|
||||||
Account* = ref object
|
Account* = object
|
||||||
nonce*: UInt256
|
nonce*: UInt256
|
||||||
balance*: UInt256
|
balance*: UInt256
|
||||||
storageRoot*: Hash256
|
storageRoot*: Hash256
|
||||||
codeHash*: Hash256
|
codeHash*: Hash256
|
||||||
|
|
||||||
rlpFields Account, nonce, balance
|
|
||||||
|
|
||||||
proc newAccount*(nonce: UInt256 = 0.u256, balance: UInt256 = 0.u256): Account =
|
proc newAccount*(nonce: UInt256 = 0.u256, balance: UInt256 = 0.u256): Account =
|
||||||
Account(nonce: nonce, balance: balance)
|
result.nonce = nonce
|
||||||
|
result.balance = balance
|
||||||
|
result.storageRoot = BLANK_ROOT_HASH
|
||||||
|
result.codeHash = EMPTY_SHA3
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, eth_common,
|
eth_common,
|
||||||
./logging, ./constants
|
./logging, ./constants
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, math, strutils, utils/padding, eth_common
|
math, strutils, utils/padding, eth_common
|
||||||
|
|
||||||
proc default(t: typedesc): t = discard
|
proc default(t: typedesc): t = discard
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ let
|
||||||
GENESIS_EXTRA_DATA* = ""
|
GENESIS_EXTRA_DATA* = ""
|
||||||
GAS_LIMIT_MINIMUM* = 5000
|
GAS_LIMIT_MINIMUM* = 5000
|
||||||
|
|
||||||
EMPTYSHA3 = "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"
|
BLANK_ROOT_HASH* = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".toDigest
|
||||||
BLANK_ROOT_HASH* = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".toDigest()
|
EMPTY_SHA3* = "883f7328a6c30727a655daff17eba3a86049871bc7839a5b71e2bc26a99c4d4c".toDigest
|
||||||
|
|
||||||
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.u256
|
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.u256
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import stint, tables, sequtils, algorithm, rlp, ranges, state_db, nimcrypto,
|
import
|
||||||
../errors, ../block_types, ../utils/header, ../constants, eth_common, byteutils,
|
tables, sequtils, algorithm,
|
||||||
./storage_types.nim, backends/memory_backend
|
rlp, ranges, state_db, nimcrypto, eth_trie/[types, hexary], eth_common, byteutils,
|
||||||
|
../errors, ../block_types, ../utils/header, ../constants, ./storage_types.nim
|
||||||
|
|
||||||
type
|
type
|
||||||
BaseChainDB* = ref object
|
BaseChainDB* = ref object
|
||||||
db*: MemoryDB
|
db*: TrieDatabaseRef
|
||||||
# TODO db*: JournalDB
|
# TODO db*: JournalDB
|
||||||
|
|
||||||
KeyType = enum
|
KeyType = enum
|
||||||
|
@ -22,13 +23,10 @@ type
|
||||||
blockNumber: BlockNumber
|
blockNumber: BlockNumber
|
||||||
index: int
|
index: int
|
||||||
|
|
||||||
proc newBaseChainDB*(db: MemoryDB): BaseChainDB =
|
proc newBaseChainDB*(db: TrieDatabaseRef): BaseChainDB =
|
||||||
new(result)
|
new(result)
|
||||||
result.db = db
|
result.db = db
|
||||||
|
|
||||||
proc contains*(self: BaseChainDB; key: Hash256): bool =
|
|
||||||
return self.db.contains(genericHashKey(key))
|
|
||||||
|
|
||||||
proc `$`*(db: BaseChainDB): string =
|
proc `$`*(db: BaseChainDB): string =
|
||||||
result = "BaseChainDB"
|
result = "BaseChainDB"
|
||||||
|
|
||||||
|
@ -37,17 +35,17 @@ proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader =
|
||||||
##
|
##
|
||||||
## Raises BlockNotFound if it is not present in the db.
|
## Raises BlockNotFound if it is not present in the db.
|
||||||
try:
|
try:
|
||||||
let blk = self.db.get(genericHashKey(blockHash))
|
let blk = self.db.get(genericHashKey(blockHash).toOpenArray).toRange
|
||||||
return decode(blk, BlockHeader)
|
return decode(blk, BlockHeader)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
||||||
|
|
||||||
proc getHash(self: BaseChainDB, key: DbKey): Hash256 {.inline.} =
|
proc getHash(self: BaseChainDB, key: DbKey): Hash256 {.inline.} =
|
||||||
rlp.decode(self.db.get(key).toRange, Hash256)
|
rlp.decode(self.db.get(key.toOpenArray).toRange, Hash256)
|
||||||
|
|
||||||
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
||||||
let k = canonicalHeadHashKey()
|
let k = canonicalHeadHashKey()
|
||||||
if k notin self.db:
|
if k.toOpenArray notin self.db:
|
||||||
raise newException(CanonicalHeadNotFound,
|
raise newException(CanonicalHeadNotFound,
|
||||||
"No canonical head set for this chain")
|
"No canonical head set for this chain")
|
||||||
return self.getBlockHeaderByHash(self.getHash(k))
|
return self.getBlockHeaderByHash(self.getHash(k))
|
||||||
|
@ -64,7 +62,7 @@ proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; n: BlockNumber): BlockH
|
||||||
self.getBlockHeaderByHash(self.lookupBlockHash(n))
|
self.getBlockHeaderByHash(self.lookupBlockHash(n))
|
||||||
|
|
||||||
proc getScore*(self: BaseChainDB; blockHash: Hash256): int =
|
proc getScore*(self: BaseChainDB; blockHash: Hash256): int =
|
||||||
rlp.decode(self.db.get(blockHashToScoreKey(blockHash)).toRange, int)
|
rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray).toRange, int)
|
||||||
|
|
||||||
iterator findNewAncestors(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
iterator findNewAncestors(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
||||||
## Returns the chain leading up from the given header until the first ancestor it has in
|
## Returns the chain leading up from the given header until the first ancestor it has in
|
||||||
|
@ -86,7 +84,8 @@ iterator findNewAncestors(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
||||||
h = self.getBlockHeaderByHash(h.parentHash)
|
h = self.getBlockHeaderByHash(h.parentHash)
|
||||||
|
|
||||||
proc addBlockNumberToHashLookup(self: BaseChainDB; header: BlockHeader) =
|
proc addBlockNumberToHashLookup(self: BaseChainDB; header: BlockHeader) =
|
||||||
self.db.set(blockNumberToHashKey(header.blockNumber), rlp.encode(header.hash))
|
self.db.put(blockNumberToHashKey(header.blockNumber).toOpenArray,
|
||||||
|
rlp.encode(header.hash).toOpenArray)
|
||||||
|
|
||||||
iterator getBlockTransactionHashes(self: BaseChainDB, blockHeader: BlockHeader): Hash256 =
|
iterator getBlockTransactionHashes(self: BaseChainDB, blockHeader: BlockHeader): Hash256 =
|
||||||
## Returns an iterable of the transaction hashes from th block specified
|
## Returns an iterable of the transaction hashes from th block specified
|
||||||
|
@ -101,7 +100,7 @@ iterator getBlockTransactionHashes(self: BaseChainDB, blockHeader: BlockHeader):
|
||||||
|
|
||||||
proc removeTransactionFromCanonicalChain(self: BaseChainDB, transactionHash: Hash256) {.inline.} =
|
proc removeTransactionFromCanonicalChain(self: BaseChainDB, transactionHash: Hash256) {.inline.} =
|
||||||
## Removes the transaction specified by the given hash from the canonical chain.
|
## Removes the transaction specified by the given hash from the canonical chain.
|
||||||
self.db.delete(transactionHashToBlockKey(transactionHash))
|
self.db.del(transactionHashToBlockKey(transactionHash).toOpenArray)
|
||||||
|
|
||||||
proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockHeader] =
|
proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockHeader] =
|
||||||
## Sets the header as the canonical chain HEAD.
|
## Sets the header as the canonical chain HEAD.
|
||||||
|
@ -125,36 +124,36 @@ proc setAsCanonicalChainHead(self: BaseChainDB; headerHash: Hash256): seq[BlockH
|
||||||
for h in newCanonicalHeaders:
|
for h in newCanonicalHeaders:
|
||||||
self.addBlockNumberToHashLookup(h)
|
self.addBlockNumberToHashLookup(h)
|
||||||
|
|
||||||
self.db.set(canonicalHeadHashKey(), rlp.encode(header.hash))
|
self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(header.hash).toOpenArray)
|
||||||
|
|
||||||
return newCanonicalHeaders
|
return newCanonicalHeaders
|
||||||
|
|
||||||
proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
||||||
## Returns True if the header with the given block hash is in our DB.
|
## Returns True if the header with the given block hash is in our DB.
|
||||||
self.contains(blockHash)
|
self.db.contains(blockHash.data)
|
||||||
|
|
||||||
iterator getBlockTransactionData(self: BaseChainDB, transactionRoot: Hash256): BytesRange =
|
iterator getBlockTransactionData(self: BaseChainDB, transactionRoot: Hash256): BytesRange =
|
||||||
doAssert(false, "TODO: Implement me")
|
var transactionDb = initHexaryTrie(self.db, transactionRoot)
|
||||||
# var transactionDb = HexaryTrie(self.db, transactionRoot)
|
var transactionIdx = 0
|
||||||
# var transactionIdx = 0
|
while true:
|
||||||
# while true:
|
let transactionKey = rlp.encode(transactionIdx).toRange
|
||||||
# var transactionKey = rlp.encode(transactionIdx)
|
if transactionKey in transactionDb:
|
||||||
# if transactionKey in transactionDb:
|
yield transactionDb.get(transactionKey)
|
||||||
# var transactionData = transactionDb[transactionKey]
|
else:
|
||||||
# yield transactionDb[transactionKey]
|
break
|
||||||
# else:
|
inc transactionIdx
|
||||||
# break
|
|
||||||
# inc transactionIdx
|
|
||||||
|
|
||||||
|
iterator getReceipts*(self: BaseChainDB; header: BlockHeader; receiptClass: typedesc): Receipt =
|
||||||
# iterator getReceipts*(self: BaseChainDB; header: BlockHeader; receiptClass: typedesc): Receipt =
|
var receiptDb = initHexaryTrie(self.db, header.receiptRoot)
|
||||||
# var receiptDb = HexaryTrie()
|
var receiptIdx = 0
|
||||||
# for receiptIdx in itertools.count():
|
while true:
|
||||||
# var receiptKey = rlp.encode(receiptIdx)
|
let receiptKey = rlp.encode(receiptIdx).toRange
|
||||||
# if receiptKey in receiptDb:
|
if receiptKey in receiptDb:
|
||||||
# var receiptData = receiptDb[receiptKey]
|
let receiptData = receiptDb.get(receiptKey)
|
||||||
# yield rlp.decode(receiptData)
|
yield rlp.decode(receiptData, receiptClass)
|
||||||
# else:
|
else:
|
||||||
# break
|
break
|
||||||
|
inc receiptIdx
|
||||||
|
|
||||||
iterator getBlockTransactions(self: BaseChainDB; transactionRoot: Hash256;
|
iterator getBlockTransactions(self: BaseChainDB; transactionRoot: Hash256;
|
||||||
transactionClass: typedesc): transactionClass =
|
transactionClass: typedesc): transactionClass =
|
||||||
|
@ -166,10 +165,12 @@ proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader
|
||||||
if not isGenesis and not self.headerExists(header.parentHash):
|
if not isGenesis and not self.headerExists(header.parentHash):
|
||||||
raise newException(ParentNotFound, "Cannot persist block header " &
|
raise newException(ParentNotFound, "Cannot persist block header " &
|
||||||
$header.hash & " with unknown parent " & $header.parentHash)
|
$header.hash & " with unknown parent " & $header.parentHash)
|
||||||
self.db.set(genericHashKey(header.hash), rlp.encode(header))
|
self.db.put(genericHashKey(header.hash).toOpenArray, rlp.encode(header).toOpenArray)
|
||||||
|
|
||||||
let score = if isGenesis: header.difficulty
|
let score = if isGenesis: header.difficulty
|
||||||
else: self.getScore(header.parentHash).u256 + header.difficulty
|
else: self.getScore(header.parentHash).u256 + header.difficulty
|
||||||
self.db.set(blockHashToScoreKey(header.hash), rlp.encode(score))
|
self.db.put(blockHashToScoreKey(header.hash).toOpenArray, rlp.encode(score).toOpenArray)
|
||||||
|
|
||||||
var headScore: int
|
var headScore: int
|
||||||
try:
|
try:
|
||||||
headScore = self.getScore(self.getCanonicalHead().hash)
|
headScore = self.getScore(self.getCanonicalHead().hash)
|
||||||
|
@ -179,18 +180,17 @@ proc persistHeaderToDb*(self: BaseChainDB; header: BlockHeader): seq[BlockHeader
|
||||||
if score > headScore.u256:
|
if score > headScore.u256:
|
||||||
result = self.setAsCanonicalChainHead(header.hash)
|
result = self.setAsCanonicalChainHead(header.hash)
|
||||||
|
|
||||||
|
|
||||||
proc addTransactionToCanonicalChain(self: BaseChainDB, txHash: Hash256,
|
proc addTransactionToCanonicalChain(self: BaseChainDB, txHash: Hash256,
|
||||||
blockHeader: BlockHeader, index: int) =
|
blockHeader: BlockHeader, index: int) =
|
||||||
let k: TransactionKey = (blockHeader.blockNumber, index)
|
let k: TransactionKey = (blockHeader.blockNumber, index)
|
||||||
self.db.set(transactionHashToBlockKey(txHash), rlp.encode(k))
|
self.db.put(transactionHashToBlockKey(txHash).toOpenArray, rlp.encode(k).toOpenArray)
|
||||||
|
|
||||||
proc persistUncles*(self: BaseChainDB, uncles: openarray[BlockHeader]): Hash256 =
|
proc persistUncles*(self: BaseChainDB, uncles: openarray[BlockHeader]): Hash256 =
|
||||||
## Persists the list of uncles to the database.
|
## Persists the list of uncles to the database.
|
||||||
## Returns the uncles hash.
|
## Returns the uncles hash.
|
||||||
let enc = rlp.encode(uncles)
|
let enc = rlp.encode(uncles)
|
||||||
result = keccak256.digest(enc.toOpenArray())
|
result = keccak256.digest(enc.toOpenArray())
|
||||||
self.db.set(genericHashKey(result), enc)
|
self.db.put(genericHashKey(result).toOpenArray, enc.toOpenArray)
|
||||||
|
|
||||||
proc persistBlockToDb*(self: BaseChainDB; blk: Block) =
|
proc persistBlockToDb*(self: BaseChainDB; blk: Block) =
|
||||||
## Persist the given block's header and uncles.
|
## Persist the given block's header and uncles.
|
||||||
|
@ -227,6 +227,5 @@ proc persistBlockToDb*(self: BaseChainDB; blk: Block) =
|
||||||
# proc clear*(self: BaseChainDB): void =
|
# proc clear*(self: BaseChainDB): void =
|
||||||
# self.db.clear()
|
# self.db.clear()
|
||||||
|
|
||||||
method getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
|
proc getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
|
||||||
# TODO
|
result = newAccountStateDB(self.db, stateRoot)
|
||||||
result = newAccountStateDB(initTable[string, string]())
|
|
||||||
|
|
|
@ -6,33 +6,44 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
eth_common, tables, nimcrypto, stint, rlp,
|
sequtils, tables,
|
||||||
|
eth_common, nimcrypto, rlp, eth_trie/[hexary, memdb],
|
||||||
../constants, ../errors, ../validation, ../account, ../logging
|
../constants, ../errors, ../validation, ../account, ../logging
|
||||||
|
|
||||||
type
|
type
|
||||||
AccountStateDB* = ref object
|
AccountStateDB* = ref object
|
||||||
db*: Table[string, BytesRange]
|
trie: HexaryTrie
|
||||||
rootHash*: Hash256 # TODO trie
|
|
||||||
|
|
||||||
proc newAccountStateDB*(db: Table[string, string], readOnly: bool = false): AccountStateDB =
|
proc rootHash*(accountDb: AccountStateDB): KeccakHash =
|
||||||
result = AccountStateDB(db: initTable[string, BytesRange]())
|
accountDb.trie.rootHash
|
||||||
|
|
||||||
|
# proc `rootHash=`*(db: var AccountStateDB, value: string) =
|
||||||
|
# TODO: self.Trie.rootHash = value
|
||||||
|
|
||||||
|
proc newAccountStateDB*(backingStore: TrieDatabaseRef,
|
||||||
|
root: KeccakHash, readOnly: bool = false): AccountStateDB =
|
||||||
|
result.new()
|
||||||
|
result.trie = initHexaryTrie(backingStore, root)
|
||||||
|
|
||||||
proc logger*(db: AccountStateDB): Logger =
|
proc logger*(db: AccountStateDB): Logger =
|
||||||
logging.getLogger("db.State")
|
logging.getLogger("db.State")
|
||||||
|
|
||||||
|
template createRangeFromAddress(address: EthAddress): ByteRange =
|
||||||
|
## XXX: The name of this proc is intentionally long, because it
|
||||||
|
## performs a memory allocation and data copying that may be eliminated
|
||||||
|
## in the future. Avoid renaming it to something similar as `toRange`, so
|
||||||
|
## it can remain searchable in the code.
|
||||||
|
toRange(@address)
|
||||||
|
|
||||||
proc getAccount(db: AccountStateDB, address: EthAddress): Account =
|
proc getAccount(db: AccountStateDB, address: EthAddress): Account =
|
||||||
# let rlpAccount = db.trie[address]
|
let recordFound = db.trie.get(createRangeFromAddress address)
|
||||||
# if not rlpAccount.isNil:
|
if recordFound.len > 0:
|
||||||
# account = rlp.decode[Account](rlpAccount)
|
result = rlp.decode(recordFound, Account)
|
||||||
# account.mutable = true
|
else:
|
||||||
# else:
|
result = newAccount()
|
||||||
# account = newAccount()
|
|
||||||
result = newAccount() # TODO
|
|
||||||
|
|
||||||
proc setAccount(db: AccountStateDB, address: EthAddress, account: Account) =
|
proc setAccount(db: AccountStateDB, address: EthAddress, account: Account) =
|
||||||
# db.trie[address] = rlp.encode[Account](account)
|
db.trie.put createRangeFromAddress(address), rlp.encode(account)
|
||||||
discard # TODO
|
|
||||||
|
|
||||||
|
|
||||||
proc getCodeHash*(db: AccountStateDB, address: EthAddress): Hash256 =
|
proc getCodeHash*(db: AccountStateDB, address: EthAddress): Hash256 =
|
||||||
validateCanonicalAddress(address, title="Storage Address")
|
validateCanonicalAddress(address, title="Storage Address")
|
||||||
|
@ -46,51 +57,55 @@ proc getBalance*(db: AccountStateDB, address: EthAddress): UInt256 =
|
||||||
|
|
||||||
proc setBalance*(db: var AccountStateDB, address: EthAddress, balance: UInt256) =
|
proc setBalance*(db: var AccountStateDB, address: EthAddress, balance: UInt256) =
|
||||||
validateCanonicalAddress(address, title="Storage Address")
|
validateCanonicalAddress(address, title="Storage Address")
|
||||||
let account = db.getAccount(address)
|
var account = db.getAccount(address)
|
||||||
account.balance = balance
|
account.balance = balance
|
||||||
db.setAccount(address, account)
|
db.setAccount(address, account)
|
||||||
|
|
||||||
proc deltaBalance*(db: var AccountStateDB, address: EthAddress, delta: UInt256) =
|
proc deltaBalance*(db: var AccountStateDB, address: EthAddress, delta: UInt256) =
|
||||||
db.setBalance(address, db.getBalance(address) + delta)
|
db.setBalance(address, db.getBalance(address) + delta)
|
||||||
|
|
||||||
|
template createTrieKeyFromSlot(slot: UInt256): ByteRange =
|
||||||
|
# XXX: This is too expensive. Similar to `createRangeFromAddress`
|
||||||
|
# Converts a number to hex big-endian representation including
|
||||||
|
# prefix and leading zeros:
|
||||||
|
@(keccak256.digest(slot.toByteArrayBE).data).toRange
|
||||||
|
# Original py-evm code:
|
||||||
|
# pad32(int_to_big_endian(slot))
|
||||||
|
|
||||||
proc setStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256, value: UInt256) =
|
proc setStorage*(db: var AccountStateDB,
|
||||||
|
address: EthAddress,
|
||||||
|
slot: UInt256, value: UInt256) =
|
||||||
#validateGte(value, 0, title="Storage Value")
|
#validateGte(value, 0, title="Storage Value")
|
||||||
#validateGte(slot, 0, title="Storage Slot")
|
#validateGte(slot, 0, title="Storage Slot")
|
||||||
validateCanonicalAddress(address, title="Storage Address")
|
validateCanonicalAddress(address, title="Storage Address")
|
||||||
|
|
||||||
# TODO
|
var account = db.getAccount(address)
|
||||||
# let account = db.getAccount(address)
|
var accountTrie = initHexaryTrie(db.trie.db, account.storageRoot)
|
||||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
let slotAsKey = createTrieKeyFromSlot slot
|
||||||
|
|
||||||
let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros
|
|
||||||
var storage = db.db
|
|
||||||
# TODO fix
|
|
||||||
if value > 0:
|
if value > 0:
|
||||||
let encodedValue = rlp.encode value.toByteArrayBE
|
let encodedValue = rlp.encode value
|
||||||
storage[slotAsKey] = encodedValue
|
accountTrie.put(slotAsKey, encodedValue)
|
||||||
else:
|
else:
|
||||||
storage.del(slotAsKey)
|
accountTrie.del(slotAsKey)
|
||||||
#storage[slotAsKey] = value
|
|
||||||
# account.storageRoot = storage.rootHash
|
|
||||||
# db.setAccount(address, account)
|
|
||||||
|
|
||||||
proc getStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256): (UInt256, bool) =
|
account.storageRoot = accountTrie.rootHash
|
||||||
|
db.setAccount(address, account)
|
||||||
|
|
||||||
|
proc getStorage*(db: AccountStateDB, address: EthAddress, slot: UInt256): (UInt256, bool) =
|
||||||
validateCanonicalAddress(address, title="Storage Address")
|
validateCanonicalAddress(address, title="Storage Address")
|
||||||
#validateGte(slot, 0, title="Storage Slot")
|
#validateGte(slot, 0, title="Storage Slot")
|
||||||
|
|
||||||
# TODO
|
let
|
||||||
# make it more correct
|
account = db.getAccount(address)
|
||||||
# for now, we just use a table
|
slotAsKey = createTrieKeyFromSlot slot
|
||||||
|
accountTrie = initHexaryTrie(db.trie.db, account.storageRoot)
|
||||||
|
|
||||||
# let account = db.GetAccount(address)
|
let
|
||||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
foundRecord = accountTrie.get(slotAsKey)
|
||||||
|
|
||||||
let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros
|
if foundRecord.len > 0:
|
||||||
var storage = db.db
|
result = (rlp.decode(foundRecord, UInt256), true)
|
||||||
if storage.hasKey(slotAsKey):
|
|
||||||
let byteRange = storage[slotAsKey]
|
|
||||||
result = (readUintBE[256](byteRange.toOpenArray), true)
|
|
||||||
else:
|
else:
|
||||||
result = (0.u256, false)
|
result = (0.u256, false)
|
||||||
|
|
||||||
|
@ -109,24 +124,21 @@ proc getNonce*(db: AccountStateDB, address: EthAddress): UInt256 =
|
||||||
let account = db.getAccount(address)
|
let account = db.getAccount(address)
|
||||||
return account.nonce
|
return account.nonce
|
||||||
|
|
||||||
proc setCode*(db: var AccountStateDB, address: EthAddress, code: string) =
|
proc toByteRange_Unnecessary*(h: KeccakHash): ByteRange =
|
||||||
|
## XXX: Another proc used to mark unnecessary conversions it the code
|
||||||
|
var s = @(h.data)
|
||||||
|
return s.toRange
|
||||||
|
|
||||||
|
proc setCode*(db: var AccountStateDB, address: EthAddress, code: ByteRange) =
|
||||||
validateCanonicalAddress(address, title="Storage Address")
|
validateCanonicalAddress(address, title="Storage Address")
|
||||||
|
|
||||||
var account = db.getAccount(address)
|
var account = db.getAccount(address)
|
||||||
|
account.codeHash = keccak256.digest code.toOpenArray
|
||||||
account.codeHash = keccak256.digest code
|
# XXX: this uses the journaldb in py-evm
|
||||||
#db.db[account.codeHash] = code
|
db.trie.put(account.codeHash.toByteRange_Unnecessary, code)
|
||||||
db.setAccount(address, account)
|
db.setAccount(address, account)
|
||||||
|
|
||||||
proc getCode*(db: var AccountStateDB, address: EthAddress): string =
|
proc getCode*(db: AccountStateDB, address: EthAddress): ByteRange =
|
||||||
let codeHash = db.getCodeHash(address)
|
let codeHash = db.getCodeHash(address)
|
||||||
#if db.db.hasKey(codeHash):
|
result = db.trie.get(codeHash.toByteRange_Unnecessary)
|
||||||
# result = db.db[codeHash]
|
|
||||||
#else:
|
|
||||||
result = ""
|
|
||||||
|
|
||||||
# proc rootHash*(db: AccountStateDB): string =
|
|
||||||
# TODO return self.Trie.rootHash
|
|
||||||
|
|
||||||
# proc `rootHash=`*(db: var AccountStateDB, value: string) =
|
|
||||||
# TODO: self.Trie.rootHash = value
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ type
|
||||||
|
|
||||||
DbKey* = object
|
DbKey* = object
|
||||||
# The first byte stores the key type. The rest are key-specific values
|
# The first byte stores the key type. The rest are key-specific values
|
||||||
data: array[33, byte]
|
data*: array[33, byte]
|
||||||
dataEndPos: uint8 # the last populated position in the data
|
dataEndPos*: uint8 # the last populated position in the data
|
||||||
|
|
||||||
StorageError* = object of Exception
|
StorageError* = object of Exception
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
constants, stint, errors, eth_common
|
constants, errors, eth_common
|
||||||
|
|
||||||
type
|
type
|
||||||
BaseTransaction* = ref object
|
BaseTransaction* = ref object
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
import eth_common, ../constants, stint, strformat, times, ../validation, rlp
|
import eth_common, ../constants, strformat, times, ../validation, rlp
|
||||||
|
|
||||||
export BlockHeader
|
export BlockHeader
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat,
|
strformat,
|
||||||
errors, constants, stint, eth_common
|
errors, constants, eth_common
|
||||||
|
|
||||||
template validateCanonicalAddress*(value: EthAddress, title: string = "Value") =
|
template validateCanonicalAddress*(value: EthAddress, title: string = "Value") =
|
||||||
# TODO: This needs to be removed
|
# TODO: This needs to be removed
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, strutils, sequtils, parseutils, sets, macros,
|
strformat, strutils, sequtils, parseutils, sets, macros,
|
||||||
|
eth_common,
|
||||||
../logging, ../constants, ./interpreter/opcode_values
|
../logging, ../constants, ./interpreter/opcode_values
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -51,6 +52,17 @@ proc read*(c: var CodeStream, size: int): seq[byte] =
|
||||||
result = @[]
|
result = @[]
|
||||||
c.pc = c.bytes.len
|
c.pc = c.bytes.len
|
||||||
|
|
||||||
|
proc readVmWord*(c: var CodeStream, n: int): UInt256 =
|
||||||
|
## Reads `n` bytes bytes from the code stream and pads
|
||||||
|
## the remaining bytes with zeros.
|
||||||
|
let result_bytes = cast[ptr array[32, byte]](addr result)
|
||||||
|
|
||||||
|
let last = min(c.pc + n, c.bytes.len)
|
||||||
|
let toWrite = last - c.pc
|
||||||
|
for i in 0 ..< toWrite : result_bytes[i] = c.bytes[last - i - 1]
|
||||||
|
for j in toWrite ..< 32: result_bytes[j] = 0
|
||||||
|
c.pc = last
|
||||||
|
|
||||||
proc len*(c: CodeStream): int =
|
proc len*(c: CodeStream): int =
|
||||||
len(c.bytes)
|
len(c.bytes)
|
||||||
|
|
||||||
|
@ -78,16 +90,15 @@ proc peek*(c: var CodeStream): Op =
|
||||||
proc updatePc*(c: var CodeStream, value: int) =
|
proc updatePc*(c: var CodeStream, value: int) =
|
||||||
c.pc = min(value, len(c))
|
c.pc = min(value, len(c))
|
||||||
|
|
||||||
macro seek*(c: var CodeStream, pc: int, handler: untyped): untyped =
|
when false:
|
||||||
let c2 = ident("c")
|
template seek*(cs: var CodeStream, pc: int, handler: untyped): untyped =
|
||||||
result = quote:
|
var anchorPc = cs.pc
|
||||||
var anchorPc = `c`.pc
|
cs.pc = pc
|
||||||
`c`.pc = `pc`
|
|
||||||
try:
|
try:
|
||||||
var `c2` = `c`
|
var c {.inject.} = cs
|
||||||
`handler`
|
handler
|
||||||
finally:
|
finally:
|
||||||
`c`.pc = anchorPc
|
cs.pc = anchorPc
|
||||||
|
|
||||||
proc isValidOpcode*(c: var CodeStream, position: int): bool =
|
proc isValidOpcode*(c: var CodeStream, position: int): bool =
|
||||||
if position >= len(c):
|
if position >= len(c):
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, strutils, sequtils, macros, stint, terminal, math, eth_common, byteutils, tables,
|
strformat, strutils, sequtils, macros, terminal, math, tables,
|
||||||
|
eth_common, byteutils,
|
||||||
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
|
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
|
||||||
./interpreter/[opcode_values,gas_meter, gas_costs],
|
./interpreter/[opcode_values,gas_meter, gas_costs],
|
||||||
./code_stream, ./memory, ./message, ./stack,
|
./code_stream, ./memory, ./message, ./stack,
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, stint,
|
strformat,
|
||||||
|
eth_common/eth_types,
|
||||||
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
||||||
|
|
||||||
proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, eth_common/eth_types,
|
eth_common/eth_types,
|
||||||
../../../logging, ../../../constants, ../../../errors,
|
../../../logging, ../../../constants, ../../../errors,
|
||||||
../../../block_types,
|
../../../block_types,
|
||||||
../../../vm/[base, stack], ../../../db/db_chain, ../../../utils/header,
|
../../../vm/[base, stack], ../../../db/db_chain, ../../../utils/header,
|
||||||
./frontier_block, ./frontier_vm_state, ./frontier_validation
|
./frontier_block, ./frontier_vm_state, ./frontier_validation
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
FrontierVM* = ref object of VM
|
FrontierVM* = ref object of VM
|
||||||
|
|
||||||
|
@ -34,4 +33,6 @@ proc newFrontierVM*(header: BlockHeader, chainDB: BaseChainDB): FrontierVM =
|
||||||
result.chainDB = chainDB
|
result.chainDB = chainDB
|
||||||
result.isStateless = true
|
result.isStateless = true
|
||||||
result.state = newFrontierVMState()
|
result.state = newFrontierVMState()
|
||||||
|
result.state.chaindb = result.chainDB
|
||||||
|
result.state.blockHeader = header
|
||||||
result.`block` = makeFrontierBlock(header, @[])
|
result.`block` = makeFrontierBlock(header, @[])
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, stint,
|
strformat,
|
||||||
|
eth_common/eth_types,
|
||||||
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
||||||
|
|
||||||
proc validateTangerineTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
proc validateTangerineTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
eth_common/eth_types,
|
||||||
../../../logging, ../../../constants, ../../../errors,
|
../../../logging, ../../../constants, ../../../errors,
|
||||||
stint,
|
|
||||||
../../../block_types,
|
../../../block_types,
|
||||||
../../../vm/[base, stack], ../../../db/db_chain, ../../../utils/header,
|
../../../vm/[base, stack], ../../../db/db_chain, ../../../utils/header,
|
||||||
./tangerine_block, ./tangerine_vm_state, ./tangerine_validation
|
./tangerine_block, ./tangerine_vm_state, ./tangerine_validation
|
||||||
|
@ -34,4 +34,6 @@ proc newTangerineVM*(header: BlockHeader, chainDB: BaseChainDB): TangerineVM =
|
||||||
result.chainDB = chainDB
|
result.chainDB = chainDB
|
||||||
result.isStateless = true
|
result.isStateless = true
|
||||||
result.state = newTangerineVMState()
|
result.state = newTangerineVMState()
|
||||||
|
result.state.chaindb = result.chainDB
|
||||||
|
result.state.blockHeader = header
|
||||||
result.`block` = makeTangerineBlock(header, @[])
|
result.`block` = makeTangerineBlock(header, @[])
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, math, eth_common, # GasInt
|
math, eth_common/eth_types,
|
||||||
../utils/[macros_gen_opcodes, utils_numeric],
|
../utils/[macros_gen_opcodes, utils_numeric],
|
||||||
./opcode_values
|
./opcode_values
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
tables, stint,
|
tables, eth_common/eth_types,
|
||||||
../../vm_types, ./opcode_values,
|
../../vm_types, ./opcode_values,
|
||||||
opcodes_impl/[arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops]
|
opcodes_impl/[arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops]
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ const
|
||||||
CallDataLoad: callDataLoad,
|
CallDataLoad: callDataLoad,
|
||||||
CallDataSize: callDataSize,
|
CallDataSize: callDataSize,
|
||||||
CallDataCopy: callDataCopy,
|
CallDataCopy: callDataCopy,
|
||||||
CodeSize: codesize,
|
CodeSize: codeSize,
|
||||||
CodeCopy: codecopy,
|
CodeCopy: codeCopy,
|
||||||
GasPrice: gasPrice, # TODO this wasn't used previously
|
GasPrice: gasPrice, # TODO this wasn't used previously
|
||||||
ExtCodeSize: extCodeSize,
|
ExtCodeSize: extCodeSize,
|
||||||
ExtCodeCopy: extCodeCopy,
|
ExtCodeCopy: extCodeCopy,
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
helpers, stint, strutils, ./impl_std_import
|
strutils,
|
||||||
|
eth_common/eth_types,
|
||||||
|
helpers, ./impl_std_import
|
||||||
|
|
||||||
proc add*(computation: var BaseComputation) =
|
proc add*(computation: var BaseComputation) =
|
||||||
# Addition
|
# Addition
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
../constants, ../computation, ../vm/stack, ../vm_state, stint
|
eth_common/eth_types,
|
||||||
|
../constants, ../computation, ../vm/stack, ../vm_state
|
||||||
|
|
||||||
proc blockhash*(computation: var BaseComputation) =
|
proc blockhash*(computation: var BaseComputation) =
|
||||||
var blockNumber = computation.stack.popInt()
|
var blockNumber = computation.stack.popInt()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, eth_common, stint,
|
strformat, eth_common,
|
||||||
# ./impl_std_import # Cannot do that due to recursive dependencies
|
# ./impl_std_import # Cannot do that due to recursive dependencies
|
||||||
# .../vm/interpreter/opcodes_impl/impl_std_import.nim imports .../vm/computation.nim
|
# .../vm/interpreter/opcodes_impl/impl_std_import.nim imports .../vm/computation.nim
|
||||||
# .../vm/computation.nim imports .../vm/interpreter/opcodes_impl/call.nim
|
# .../vm/computation.nim imports .../vm/interpreter/opcodes_impl/call.nim
|
||||||
|
|
|
@ -18,11 +18,17 @@ quasiBoolean(sgt, `>`, signed=true) # Signed Greater Comparison
|
||||||
|
|
||||||
quasiBoolean(eq, `==`) # Equality
|
quasiBoolean(eq, `==`) # Equality
|
||||||
|
|
||||||
quasiBoolean(andOp, `and`, nonzero=true) # Bitwise And
|
proc andOp*(computation: var BaseComputation) =
|
||||||
|
let (lhs, rhs) = computation.stack.popInt(2)
|
||||||
|
computation.stack.push(lhs and rhs)
|
||||||
|
|
||||||
quasiBoolean(orOp, `or`, nonzero=true) # Bitwise Or
|
proc orOp*(computation: var BaseComputation) =
|
||||||
|
let (lhs, rhs) = computation.stack.popInt(2)
|
||||||
|
computation.stack.push(lhs or rhs)
|
||||||
|
|
||||||
quasiBoolean(xorOp, `xor`, nonzero=true) # Bitwise XOr
|
proc xorOp*(computation: var BaseComputation) =
|
||||||
|
let (lhs, rhs) = computation.stack.popInt(2)
|
||||||
|
computation.stack.push(lhs xor rhs)
|
||||||
|
|
||||||
# TODO use isZero from Stint
|
# TODO use isZero from Stint
|
||||||
proc iszero*(computation: var BaseComputation) =
|
proc iszero*(computation: var BaseComputation) =
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat,
|
strformat,
|
||||||
./impl_std_import
|
ranges/typedranges,
|
||||||
|
./impl_std_import,
|
||||||
|
../../../db/state_db
|
||||||
|
|
||||||
proc balance*(computation: var BaseComputation) =
|
proc balance*(computation: var BaseComputation) =
|
||||||
let address = computation.stack.popAddress()
|
let address = computation.stack.popAddress()
|
||||||
var balance: Int256
|
let balance = computation.vmState.readOnlyStateDB.getBalance(address)
|
||||||
# TODO computation.vmState.stateDB(read_only=True):
|
computation.stack.push balance
|
||||||
# balance = db.getBalance(address)
|
|
||||||
# computation.stack.push(balance)
|
|
||||||
|
|
||||||
proc origin*(computation: var BaseComputation) =
|
proc origin*(computation: var BaseComputation) =
|
||||||
computation.stack.push(computation.msg.origin)
|
computation.stack.push(computation.msg.origin)
|
||||||
|
@ -25,18 +25,53 @@ proc address*(computation: var BaseComputation) =
|
||||||
proc caller*(computation: var BaseComputation) =
|
proc caller*(computation: var BaseComputation) =
|
||||||
computation.stack.push(computation.msg.sender)
|
computation.stack.push(computation.msg.sender)
|
||||||
|
|
||||||
|
|
||||||
proc callValue*(computation: var BaseComputation) =
|
proc callValue*(computation: var BaseComputation) =
|
||||||
computation.stack.push(computation.msg.value)
|
computation.stack.push(computation.msg.value)
|
||||||
|
|
||||||
|
proc writePaddedResult(mem: var Memory,
|
||||||
|
data: openarray[byte],
|
||||||
|
memPos, dataPos, len: Natural,
|
||||||
|
paddingValue = 0.byte) =
|
||||||
|
mem.extend(memPos, len)
|
||||||
|
|
||||||
|
let dataEndPosition = dataPos + len - 1
|
||||||
|
if dataEndPosition < data.len:
|
||||||
|
mem.write(memPos, data[dataPos .. dataEndPosition])
|
||||||
|
else:
|
||||||
|
var presentElements = data.len - dataPos
|
||||||
|
if presentElements > 0:
|
||||||
|
mem.write(memPos, data.toOpenArray(dataPos, data.len - 1))
|
||||||
|
else:
|
||||||
|
presentElements = 0
|
||||||
|
|
||||||
|
mem.writePaddingBytes(memPos + presentElements,
|
||||||
|
len - presentElements,
|
||||||
|
paddingValue)
|
||||||
|
|
||||||
proc callDataLoad*(computation: var BaseComputation) =
|
proc callDataLoad*(computation: var BaseComputation) =
|
||||||
# Load call data into memory
|
# Load call data into memory
|
||||||
let startPosition = computation.stack.popInt.toInt
|
let origDataPos = computation.stack.popInt
|
||||||
let value = computation.msg.data[startPosition ..< startPosition + 32]
|
if origDataPos >= computation.msg.data.len:
|
||||||
let paddedValue = padRight(value, 32, 0.byte)
|
computation.stack.push(0)
|
||||||
let normalizedValue = paddedValue.lStrip(0.byte)
|
return
|
||||||
computation.stack.push(normalizedValue)
|
|
||||||
|
|
||||||
|
let
|
||||||
|
dataPos = origDataPos.toInt
|
||||||
|
dataEndPosition = dataPos + 31
|
||||||
|
|
||||||
|
if dataEndPosition < computation.msg.data.len:
|
||||||
|
computation.stack.push(computation.msg.data[dataPos .. dataEndPosition])
|
||||||
|
else:
|
||||||
|
var bytes: array[32, byte]
|
||||||
|
var presentBytes = min(computation.msg.data.len - dataPos, 32)
|
||||||
|
|
||||||
|
if presentBytes > 0:
|
||||||
|
copyMem(addr bytes[0], addr computation.msg.data[dataPos], presentBytes)
|
||||||
|
else:
|
||||||
|
presentBytes = 0
|
||||||
|
|
||||||
|
for i in presentBytes ..< 32: bytes[i] = 0
|
||||||
|
computation.stack.push(bytes)
|
||||||
|
|
||||||
proc callDataSize*(computation: var BaseComputation) =
|
proc callDataSize*(computation: var BaseComputation) =
|
||||||
let size = computation.msg.data.len.u256
|
let size = computation.msg.data.len.u256
|
||||||
|
@ -52,19 +87,15 @@ proc callDataCopy*(computation: var BaseComputation) =
|
||||||
reason="CALLDATACOPY fee")
|
reason="CALLDATACOPY fee")
|
||||||
|
|
||||||
let (memPos, callPos, len) = (memStartPosition.toInt, calldataStartPosition.toInt, size.toInt)
|
let (memPos, callPos, len) = (memStartPosition.toInt, calldataStartPosition.toInt, size.toInt)
|
||||||
computation.memory.extend(memPos, len)
|
|
||||||
|
|
||||||
let value = computation.msg.data[callPos ..< callPos + len]
|
computation.memory.writePaddedResult(computation.msg.data,
|
||||||
let paddedValue = padRight(value, len, 0.byte)
|
memPos, callPos, len)
|
||||||
computation.memory.write(memPos, paddedValue)
|
|
||||||
|
|
||||||
|
proc codeSize*(computation: var BaseComputation) =
|
||||||
proc codesize*(computation: var BaseComputation) =
|
|
||||||
let size = computation.code.len.u256
|
let size = computation.code.len.u256
|
||||||
computation.stack.push(size)
|
computation.stack.push(size)
|
||||||
|
|
||||||
|
proc codeCopy*(computation: var BaseComputation) =
|
||||||
proc codecopy*(computation: var BaseComputation) =
|
|
||||||
let (memStartPosition,
|
let (memStartPosition,
|
||||||
codeStartPosition,
|
codeStartPosition,
|
||||||
size) = computation.stack.popInt(3)
|
size) = computation.stack.popInt(3)
|
||||||
|
@ -74,26 +105,16 @@ proc codecopy*(computation: var BaseComputation) =
|
||||||
reason="CODECOPY: word gas cost")
|
reason="CODECOPY: word gas cost")
|
||||||
|
|
||||||
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
||||||
computation.memory.extend(memPos, len)
|
|
||||||
|
|
||||||
# TODO
|
computation.memory.writePaddedResult(computation.code.bytes, memPos, codePos, len)
|
||||||
# with computation.code.seek(code_start_position):
|
|
||||||
# code_bytes = computation.code.read(size)
|
|
||||||
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
|
|
||||||
# computation.memory.write(mem_start_position, size, padded_code_bytes)
|
|
||||||
|
|
||||||
|
proc gasPrice*(computation: var BaseComputation) =
|
||||||
proc gasprice*(computation: var BaseComputation) =
|
|
||||||
computation.stack.push(computation.msg.gasPrice.u256)
|
computation.stack.push(computation.msg.gasPrice.u256)
|
||||||
|
|
||||||
|
|
||||||
proc extCodeSize*(computation: var BaseComputation) =
|
proc extCodeSize*(computation: var BaseComputation) =
|
||||||
let account = computation.stack.popAddress()
|
let account = computation.stack.popAddress()
|
||||||
# TODO
|
let codeSize = computation.vmState.readOnlyStateDB.getCode(account).len
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
computation.stack.push uint(codeSize)
|
||||||
# code_size = len(state_db.get_code(account))
|
|
||||||
|
|
||||||
# computation.stack.push(code_size)
|
|
||||||
|
|
||||||
proc extCodeCopy*(computation: var BaseComputation) =
|
proc extCodeCopy*(computation: var BaseComputation) =
|
||||||
let account = computation.stack.popAddress()
|
let account = computation.stack.popAddress()
|
||||||
|
@ -105,15 +126,9 @@ proc extCodeCopy*(computation: var BaseComputation) =
|
||||||
)
|
)
|
||||||
|
|
||||||
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
||||||
computation.memory.extend(memPos, len)
|
let codeBytes = computation.vmState.readOnlyStateDB.getCode(account)
|
||||||
|
|
||||||
|
computation.memory.writePaddedResult(codeBytes.toOpenArray, memPos, codePos, len)
|
||||||
# TODO:
|
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
|
||||||
# code = state_db.get_code(account)
|
|
||||||
# code_bytes = code[code_start_position:code_start_position + size]
|
|
||||||
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
|
|
||||||
# computation.memory.write(mem_start_position, size, padded_code_bytes)
|
|
||||||
|
|
||||||
proc returnDataSize*(computation: var BaseComputation) =
|
proc returnDataSize*(computation: var BaseComputation) =
|
||||||
let size = computation.returnData.len.u256
|
let size = computation.returnData.len.u256
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import macros, stint
|
import
|
||||||
|
macros,
|
||||||
|
eth_common/eth_types
|
||||||
|
|
||||||
template pushRes*: untyped =
|
template pushRes*: untyped =
|
||||||
computation.stack.push(res)
|
computation.stack.push(res)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, stint/lenient_stint,
|
eth_common/eth_types, stint/lenient_stint,
|
||||||
../../../constants, ../../../vm_state, ../../../vm_types, ../../../vm_types,
|
../../../constants, ../../../vm_state, ../../../vm_types, ../../../vm_types,
|
||||||
../../../errors, ../../../logging, ../../../utils/padding, ../../../utils/bytes,
|
../../../errors, ../../../logging, ../../../utils/padding, ../../../utils/bytes,
|
||||||
../../stack, ../../computation, ../../stack, ../../memory, ../../message,
|
../../stack, ../../computation, ../../stack, ../../memory, ../../message,
|
||||||
|
@ -14,7 +14,7 @@ import
|
||||||
../opcode_values, ../gas_meter, ../gas_costs
|
../opcode_values, ../gas_meter, ../gas_costs
|
||||||
|
|
||||||
export
|
export
|
||||||
stint, lenient_stint,
|
eth_types, lenient_stint,
|
||||||
constants, vm_state, vm_types, vm_types,
|
constants, vm_state, vm_types, vm_types,
|
||||||
errors, logging, padding, bytes,
|
errors, logging, padding, bytes,
|
||||||
stack, computation, stack, memory, message,
|
stack, computation, stack, memory, message,
|
||||||
|
|
|
@ -23,14 +23,7 @@ macro pushXX(size: static[int]): untyped =
|
||||||
let name = ident(&"push{size}")
|
let name = ident(&"push{size}")
|
||||||
result = quote:
|
result = quote:
|
||||||
proc `name`*(`computation`: var BaseComputation) =
|
proc `name`*(`computation`: var BaseComputation) =
|
||||||
let `value` = `computation`.code.read(`size`)
|
`computation`.stack.push `computation`.code.readVmWord(`size`)
|
||||||
let stripped = `value`.toString.strip(0.char)
|
|
||||||
if stripped.len == 0:
|
|
||||||
`computation`.stack.push(0.u256)
|
|
||||||
else:
|
|
||||||
let paddedValue = `value`.padRight(`size`, 0.byte)
|
|
||||||
`computation`.stack.push(paddedValue)
|
|
||||||
|
|
||||||
|
|
||||||
pushXX(1)
|
pushXX(1)
|
||||||
pushXX(2)
|
pushXX(2)
|
||||||
|
|
|
@ -10,7 +10,6 @@ import
|
||||||
../../../utils/header,
|
../../../utils/header,
|
||||||
../../../db/[db_chain, state_db]
|
../../../db/[db_chain, state_db]
|
||||||
|
|
||||||
|
|
||||||
{.this: computation.}
|
{.this: computation.}
|
||||||
{.experimental.}
|
{.experimental.}
|
||||||
|
|
||||||
|
@ -20,32 +19,26 @@ using
|
||||||
proc sstore*(computation) =
|
proc sstore*(computation) =
|
||||||
let (slot, value) = stack.popInt(2)
|
let (slot, value) = stack.popInt(2)
|
||||||
|
|
||||||
var currentValue = 0.u256
|
var (currentValue, existing) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.storageAddress, slot)
|
||||||
var existing = false
|
|
||||||
|
|
||||||
computation.vmState.db(readOnly=false):
|
|
||||||
(currentValue, existing) = db.getStorage(computation.msg.storageAddress, slot)
|
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: not existing)
|
gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: not existing)
|
||||||
(gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(currentValue, gasParam)
|
(gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(currentValue, gasParam)
|
||||||
|
|
||||||
computation.gasMeter.consumeGas(gasCost, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} ({currentValue})")
|
computation.gasMeter.consumeGas(gasCost, &"SSTORE: {computation.msg.storageAddress}[{slot}] -> {value} ({currentValue})")
|
||||||
|
|
||||||
if gasRefund > 0:
|
if gasRefund > 0:
|
||||||
computation.gasMeter.refundGas(gasRefund)
|
computation.gasMeter.refundGas(gasRefund)
|
||||||
|
|
||||||
computation.vmState.db(readOnly=false):
|
computation.vmState.mutateStateDB:
|
||||||
db.setStorage(computation.msg.storageAddress, slot, value)
|
db.setStorage(computation.msg.storageAddress, slot, value)
|
||||||
|
|
||||||
proc sload*(computation) =
|
proc sload*(computation) =
|
||||||
let slot = stack.popInt()
|
let slot = stack.popInt()
|
||||||
var value = 2.u256
|
let (value, found) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.storageAddress, slot)
|
||||||
|
if found:
|
||||||
|
computation.stack.push value
|
||||||
|
else:
|
||||||
|
# XXX: raise exception?
|
||||||
|
discard
|
||||||
|
|
||||||
# TODO: with
|
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
|
||||||
# value = state_db.get_storage(
|
|
||||||
# address=computation.msg.storage_address,
|
|
||||||
# slot=slot,
|
|
||||||
# )
|
|
||||||
computation.stack.push(value)
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import
|
import
|
||||||
strformat,
|
strformat,
|
||||||
./call, ./impl_std_import,
|
./call, ./impl_std_import,
|
||||||
stint, byteutils, eth_common
|
byteutils, eth_common
|
||||||
|
|
||||||
{.this: computation.}
|
{.this: computation.}
|
||||||
{.experimental.}
|
{.experimental.}
|
||||||
|
@ -32,7 +32,7 @@ method runLogic*(create: Create, computation) =
|
||||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||||
computation.memory.extend(pos, len)
|
computation.memory.extend(pos, len)
|
||||||
|
|
||||||
# TODO: with
|
# TODO: with ZZZZ
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||||
# insufficient_funds = state_db.get_balance(
|
# insufficient_funds = state_db.get_balance(
|
||||||
# computation.msg.storage_address) < value
|
# computation.msg.storage_address) < value
|
||||||
|
@ -94,7 +94,7 @@ method runLogic*(create: CreateByzantium, computation) =
|
||||||
|
|
||||||
proc selfdestructEIP150(computation) =
|
proc selfdestructEIP150(computation) =
|
||||||
let beneficiary = stack.popAddress()
|
let beneficiary = stack.popAddress()
|
||||||
# TODO: with
|
# TODO: with ZZZZ
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||||
# if not state_db.account_exists(beneficiary):
|
# if not state_db.account_exists(beneficiary):
|
||||||
# computation.gas_meter.consume_gas(
|
# computation.gas_meter.consume_gas(
|
||||||
|
@ -105,7 +105,7 @@ proc selfdestructEIP150(computation) =
|
||||||
|
|
||||||
proc selfdestructEIP161(computation) =
|
proc selfdestructEIP161(computation) =
|
||||||
let beneficiary = stack.popAddress()
|
let beneficiary = stack.popAddress()
|
||||||
# TODO: with
|
# TODO: with ZZZZ
|
||||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||||
# is_dead = (
|
# is_dead = (
|
||||||
# not state_db.account_exists(beneficiary) or
|
# not state_db.account_exists(beneficiary) or
|
||||||
|
@ -119,7 +119,7 @@ proc selfdestructEIP161(computation) =
|
||||||
# _selfdestruct(computation, beneficiary)
|
# _selfdestruct(computation, beneficiary)
|
||||||
|
|
||||||
proc selfdestruct(computation; beneficiary: EthAddress) =
|
proc selfdestruct(computation; beneficiary: EthAddress) =
|
||||||
discard # TODO: with
|
discard # TODO: with ZZZZ
|
||||||
# with computation.vm_state.state_db() as state_db:
|
# with computation.vm_state.state_db() as state_db:
|
||||||
# local_balance = state_db.get_balance(computation.msg.storage_address)
|
# local_balance = state_db.get_balance(computation.msg.storage_address)
|
||||||
# beneficiary_balance = state_db.get_balance(beneficiary)
|
# beneficiary_balance = state_db.get_balance(beneficiary)
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
|
eth_common/eth_types,
|
||||||
../../db/db_chain, ../../constants,
|
../../db/db_chain, ../../constants,
|
||||||
../../utils/header,
|
../../utils/header,
|
||||||
../base,
|
../base,
|
||||||
../forks/f20150730_frontier/frontier_vm,
|
../forks/f20150730_frontier/frontier_vm,
|
||||||
../forks/f20161018_tangerine_whistle/tangerine_vm,
|
../forks/f20161018_tangerine_whistle/tangerine_vm
|
||||||
stint
|
|
||||||
|
|
||||||
# Note (mamy): refactoring is in progress (2018-05-23), this is redundant with
|
# Note (mamy): refactoring is in progress (2018-05-23), this is redundant with
|
||||||
# - `Chain` in src/chain.nim, to be honest I don't understand the need of this abstraction at the moment
|
# - `Chain` in src/chain.nim, to be honest I don't understand the need of this abstraction at the moment
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
sequtils, stint,
|
sequtils,
|
||||||
|
eth_common/eth_types,
|
||||||
../constants, ../errors, ../logging, ../validation, ../utils/bytes,
|
../constants, ../errors, ../logging, ../validation, ../utils/bytes,
|
||||||
./utils/utils_numeric
|
./utils/utils_numeric
|
||||||
|
|
||||||
|
@ -24,10 +25,10 @@ proc len*(memory: Memory): int =
|
||||||
result = memory.bytes.len
|
result = memory.bytes.len
|
||||||
|
|
||||||
|
|
||||||
proc extend*(memory: var Memory; startPosition: Natural; size: Natural) =
|
proc extend*(memory: var Memory; startPos: Natural; size: Natural) =
|
||||||
if size == 0:
|
if size == 0:
|
||||||
return
|
return
|
||||||
var newSize = ceil32(startPosition + size)
|
var newSize = ceil32(startPos + size)
|
||||||
if newSize <= len(memory):
|
if newSize <= len(memory):
|
||||||
return
|
return
|
||||||
var sizeToExtend = newSize - len(memory)
|
var sizeToExtend = newSize - len(memory)
|
||||||
|
@ -37,27 +38,35 @@ proc newMemory*(size: Natural): Memory =
|
||||||
result = newMemory()
|
result = newMemory()
|
||||||
result.extend(0, size)
|
result.extend(0, size)
|
||||||
|
|
||||||
proc read*(memory: var Memory, startPosition: Natural, size: Natural): seq[byte] =
|
proc read*(memory: var Memory, startPos: Natural, size: Natural): seq[byte] =
|
||||||
result = memory.bytes[startPosition ..< (startPosition + size)]
|
result = memory.bytes[startPos ..< (startPos + size)]
|
||||||
|
|
||||||
proc write*(memory: var Memory, startPosition: Natural, value: openarray[byte]) =
|
proc write*(memory: var Memory, startPos: Natural, value: openarray[byte]) =
|
||||||
let size = value.len
|
let size = value.len
|
||||||
if size == 0:
|
if size == 0:
|
||||||
return
|
return
|
||||||
#echo size
|
#echo size
|
||||||
#echo startPosition
|
#echo startPos
|
||||||
#validateGte(startPosition, 0)
|
#validateGte(startPos, 0)
|
||||||
#validateGte(size, 0)
|
#validateGte(size, 0)
|
||||||
validateLte(startPosition + size, memory.len)
|
validateLte(startPos + size, memory.len)
|
||||||
let index = memory.len
|
let index = memory.len
|
||||||
if memory.len < startPosition + size:
|
if memory.len < startPos + size:
|
||||||
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size))) # TODO: better logarithmic scaling?
|
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPos + size))) # TODO: better logarithmic scaling?
|
||||||
|
|
||||||
for z, b in value:
|
for z, b in value:
|
||||||
memory.bytes[z + startPosition] = b
|
memory.bytes[z + startPos] = b
|
||||||
|
|
||||||
template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) =
|
proc writePaddingBytes*(memory: var Memory,
|
||||||
memory.write(startPosition, value.toBytes)
|
startPos, numberOfBytes: Natural,
|
||||||
|
paddingValue = 0.byte) =
|
||||||
|
let endPos = startPos + numberOfBytes
|
||||||
|
assert endPos < memory.len
|
||||||
|
for i in startPos ..< endPos:
|
||||||
|
memory.bytes[i] = paddingValue
|
||||||
|
|
||||||
|
template write*(memory: var Memory, startPos: Natural, size: Natural, value: cstring) =
|
||||||
|
memory.write(startPos, value.toBytes)
|
||||||
# TODO ~ O(n^3):
|
# TODO ~ O(n^3):
|
||||||
# - there is a string allocation with $ (?)
|
# - there is a string allocation with $ (?)
|
||||||
# - then a conversion to seq (= new allocation) with toBytes
|
# - then a conversion to seq (= new allocation) with toBytes
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, eth_common,
|
eth_common,
|
||||||
../logging, ../constants, ../validation, ../vm_types
|
../logging, ../constants, ../validation, ../vm_types
|
||||||
|
|
||||||
proc `origin=`*(message: var Message, value: EthAddress) =
|
proc `origin=`*(message: var Message, value: EthAddress) =
|
||||||
message.internalOrigin = value
|
message.internalOrigin = value
|
||||||
|
@ -59,7 +59,10 @@ proc newMessage*(
|
||||||
|
|
||||||
result.data = data
|
result.data = data
|
||||||
|
|
||||||
result.internalOrigin = options.origin
|
if options.origin != ZERO_ADDRESS:
|
||||||
|
result.internalOrigin = options.origin
|
||||||
|
else:
|
||||||
|
result.internalOrigin = sender
|
||||||
|
|
||||||
validateGte(options.depth, minimum=0, title="Message.depth")
|
validateGte(options.depth, minimum=0, title="Message.depth")
|
||||||
result.depth = options.depth
|
result.depth = options.depth
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
|
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
|
||||||
../errors, ../validation, ./utils/utils_numeric, ../constants, stint, ../logging, .. / utils / bytes
|
../errors, ../validation, ./utils/utils_numeric, ../constants, ../logging, .. / utils / bytes
|
||||||
|
|
||||||
type
|
type
|
||||||
Stack* = ref object of RootObj
|
Stack* = ref object of RootObj
|
||||||
|
@ -29,12 +29,12 @@ proc toStackElement(v: EthAddress, elem: var StackElement) {.inline.} = elem = b
|
||||||
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem = readUintBE[256](v.data)
|
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem = readUintBE[256](v.data)
|
||||||
|
|
||||||
proc fromStackElement(elem: StackElement, v: var UInt256) {.inline.} = v = elem
|
proc fromStackElement(elem: StackElement, v: var UInt256) {.inline.} = v = elem
|
||||||
proc fromStackElement(elem: StackElement, v: var EthAddress) {.inline.} = v[0 .. ^1] = elem.toByteArrayBE().toOpenArray(0, 19)
|
proc fromStackElement(elem: StackElement, v: var EthAddress) {.inline.} = v[0 .. ^1] = elem.toByteArrayBE().toOpenArray(12, 31)
|
||||||
proc fromStackElement(elem: StackElement, v: var Hash256) {.inline.} = v.data = elem.toByteArrayBE()
|
proc fromStackElement(elem: StackElement, v: var Hash256) {.inline.} = v.data = elem.toByteArrayBE()
|
||||||
|
|
||||||
proc toStackElement(v: seq[byte], elem: var StackElement) {.inline.} =
|
proc toStackElement(v: openarray[byte], elem: var StackElement) {.inline.} =
|
||||||
# TODO: This needs to go
|
# TODO: This needs to go
|
||||||
validateStackItem(v)
|
# validateStackItem(v)
|
||||||
elem = bigEndianToInt(v)
|
elem = bigEndianToInt(v)
|
||||||
|
|
||||||
proc pushAux[T](stack: var Stack, value: T) =
|
proc pushAux[T](stack: var Stack, value: T) =
|
||||||
|
@ -45,7 +45,7 @@ proc pushAux[T](stack: var Stack, value: T) =
|
||||||
proc push*(stack: var Stack, value: uint | UInt256 | EthAddress | Hash256) {.inline.} =
|
proc push*(stack: var Stack, value: uint | UInt256 | EthAddress | Hash256) {.inline.} =
|
||||||
pushAux(stack, value)
|
pushAux(stack, value)
|
||||||
|
|
||||||
proc push*(stack: var Stack, value: seq[byte]) {.inline.} =
|
proc push*(stack: var Stack, value: openarray[byte]) {.inline.} =
|
||||||
# TODO: This needs to go...
|
# TODO: This needs to go...
|
||||||
pushAux(stack, value)
|
pushAux(stack, value)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, strformat, strutils, sequtils, endians, macros, rlp,
|
strformat, strutils, sequtils, endians, macros,
|
||||||
|
eth_common/eth_types, rlp,
|
||||||
../../constants, ../../utils/padding
|
../../constants, ../../utils/padding
|
||||||
|
|
||||||
# some methods based on py-evm utils/numeric
|
# some methods based on py-evm utils/numeric
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
macros, strformat, tables,
|
macros, strformat, tables,
|
||||||
stint, eth_common,
|
eth_common,
|
||||||
./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db],
|
./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db],
|
||||||
./utils/header
|
./utils/header
|
||||||
|
|
||||||
|
@ -77,31 +77,46 @@ method getAncestorHash*(vmState: BaseVMState, blockNumber: BlockNumber): Hash256
|
||||||
var header = vmState.prevHeaders[idx]
|
var header = vmState.prevHeaders[idx]
|
||||||
result = header.hash
|
result = header.hash
|
||||||
|
|
||||||
macro db*(vmState: untyped, readOnly: untyped, handler: untyped): untyped =
|
when false:
|
||||||
# vm.state.db:
|
# this was an older version of `mutateStateDB`, kept here for reference
|
||||||
# setupStateDB(fixture{"pre"}, stateDb)
|
# until `mutateStateDB` is fully implemented.
|
||||||
# code = db.getCode(fixture{"exec"}{"address"}.getStr)
|
macro db*(vmState: untyped, readOnly: bool, handler: untyped): untyped =
|
||||||
let db = ident("db")
|
# vm.state.db:
|
||||||
result = quote:
|
# setupStateDB(fixture{"pre"}, stateDb)
|
||||||
block:
|
# code = db.getCode(fixture{"exec"}{"address"}.getStr)
|
||||||
var `db` = `vmState`.chaindb.getStateDB(`vmState`.blockHeader.stateRoot, `readOnly`)
|
let db = ident("db")
|
||||||
`handler`
|
result = quote:
|
||||||
if `readOnly`:
|
block:
|
||||||
# This acts as a secondary check that no mutation took place for
|
var `db` = `vmState`.chaindb.getStateDB(`vmState`.blockHeader.stateRoot, `readOnly`)
|
||||||
# read_only databases.
|
`handler`
|
||||||
assert `db`.rootHash == `vmState`.blockHeader.stateRoot
|
if `readOnly`:
|
||||||
elif `vmState`.blockHeader.stateRoot != `db`.rootHash:
|
# This acts as a secondary check that no mutation took place for
|
||||||
`vmState`.blockHeader.stateRoot = `db`.rootHash
|
# read_only databases.
|
||||||
|
assert `db`.rootHash == `vmState`.blockHeader.stateRoot
|
||||||
|
elif `vmState`.blockHeader.stateRoot != `db`.rootHash:
|
||||||
|
`vmState`.blockHeader.stateRoot = `db`.rootHash
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
# `vmState`.accessLogs.reads.update(`db`.db.accessLogs.reads)
|
# `vmState`.accessLogs.reads.update(`db`.db.accessLogs.reads)
|
||||||
# `vmState`.accessLogs.writes.update(`db`.db.accessLogs.writes)
|
# `vmState`.accessLogs.writes.update(`db`.db.accessLogs.writes)
|
||||||
|
|
||||||
# remove the reference to the underlying `db` object to ensure that no
|
# remove the reference to the underlying `db` object to ensure that no
|
||||||
# further modifications can occur using the `State` object after
|
# further modifications can occur using the `State` object after
|
||||||
# leaving the context.
|
# leaving the context.
|
||||||
# TODO `db`.db = nil
|
# TODO `db`.db = nil
|
||||||
# state._trie = None
|
# state._trie = None
|
||||||
|
|
||||||
|
template mutateStateDB*(vmState: BaseVMState, body: untyped) =
|
||||||
|
# This should provide more clever change handling in the future
|
||||||
|
block:
|
||||||
|
let initialStateRoot = vmState.blockHeader.stateRoot
|
||||||
|
var db {.inject.} = vmState.chaindb.getStateDB(initialStateRoot, false)
|
||||||
|
|
||||||
|
body
|
||||||
|
|
||||||
|
let finalStateRoot = db.rootHash
|
||||||
|
if finalStateRoot != initialStateRoot:
|
||||||
|
vmState.blockHeader.stateRoot = finalStateRoot
|
||||||
|
|
||||||
proc readOnlyStateDB*(vmState: BaseVMState): AccountStateDB {.inline.}=
|
proc readOnlyStateDB*(vmState: BaseVMState): AccountStateDB {.inline.}=
|
||||||
vmState.chaindb.getStateDb(Hash256(), readOnly = true)
|
vmState.chaindb.getStateDb(vmState.blockHeader.stateRoot, readOnly = true)
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
tables, stint, eth_common,
|
tables,
|
||||||
|
eth_common,
|
||||||
./constants, ./vm_state, ./logging,
|
./constants, ./vm_state, ./logging,
|
||||||
./vm/[memory, stack, code_stream],
|
./vm/[memory, stack, code_stream],
|
||||||
./vm/interpreter/[gas_costs, opcode_values] # TODO - will be hidden at a lower layer
|
./vm/interpreter/[gas_costs, opcode_values] # TODO - will be hidden at a lower layer
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ./test_code_stream,
|
when false:
|
||||||
./test_gas_meter,
|
import ./test_code_stream,
|
||||||
./test_memory,
|
./test_gas_meter,
|
||||||
./test_stack,
|
./test_memory,
|
||||||
./test_opcode,
|
./test_stack,
|
||||||
./test_storage_backends
|
./test_opcode,
|
||||||
# ./test_vm_json
|
./test_storage_backends
|
||||||
|
|
||||||
|
when true:
|
||||||
|
import ./test_vm_json
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import unittest, macros, strformat,
|
import
|
||||||
stint,
|
unittest, macros, strformat,
|
||||||
../nimbus/[vm_types, errors, logging, vm/interpreter]
|
eth_common/eth_types,
|
||||||
|
../nimbus/[vm_types, errors, logging, vm/interpreter]
|
||||||
|
|
||||||
# TODO: quicktest
|
# TODO: quicktest
|
||||||
# PS: parametrize can be easily immitated, but still quicktests would be even more useful
|
# PS: parametrize can be easily immitated, but still quicktests would be even more useful
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
||||||
stint, byteutils, eth_common, eth_keys,
|
byteutils, eth_common, eth_keys, ranges/typedranges,
|
||||||
../nimbus/utils/[address, padding],
|
../nimbus/utils/[address, padding],
|
||||||
../nimbus/[vm_state, constants],
|
../nimbus/[vm_state, constants],
|
||||||
../nimbus/db/[db_chain, state_db],
|
../nimbus/db/[db_chain, state_db],
|
||||||
|
@ -19,10 +19,15 @@ type
|
||||||
proc validTest*(folder: string, name: string): bool =
|
proc validTest*(folder: string, name: string): bool =
|
||||||
# tests we want to skip or which segfault will be skipped here
|
# tests we want to skip or which segfault will be skipped here
|
||||||
# TODO fix
|
# TODO fix
|
||||||
|
#if true:
|
||||||
|
# return "or0" in name
|
||||||
|
#if true:
|
||||||
|
# return folder == "vmEnvironmentalInfo"
|
||||||
|
|
||||||
result = "calldatacopy" notin name and
|
result = "calldatacopy" notin name and
|
||||||
"balanceAddressInputTooBigRightMyAddress." notin name and
|
"balanceAddressInputTooBigRightMyAddress." notin name and
|
||||||
"callstatelessToReturn1" notin name and
|
"callstatelessToReturn1" notin name and
|
||||||
folder notin @["vmRandomTest", "vmSystemOperations", "vmPerformance", "vmEnvironmentalInfo"]
|
folder notin @["vmRandomTest", "vmSystemOperations", "vmPerformance"]
|
||||||
#result = name == "exp2.json"
|
#result = name == "exp2.json"
|
||||||
|
|
||||||
macro jsonTest*(s: static[string], handler: untyped): untyped =
|
macro jsonTest*(s: static[string], handler: untyped): untyped =
|
||||||
|
@ -76,22 +81,48 @@ macro jsonTest*(s: static[string], handler: untyped): untyped =
|
||||||
raw.add("OK: " & $okCount & "/" & $sum & " Fail: " & $failCount & "/" & $sum & " Skip: " & $skipCount & "/" & $sum & "\n")
|
raw.add("OK: " & $okCount & "/" & $sum & " Fail: " & $failCount & "/" & $sum & " Skip: " & $skipCount & "/" & $sum & "\n")
|
||||||
writeFile(`s` & ".md", raw)
|
writeFile(`s` & ".md", raw)
|
||||||
|
|
||||||
proc accountFromHex(s: string): EthAddress = hexToByteArray(s, result)
|
proc ethAddressFromHex(s: string): EthAddress = hexToByteArray(s, result)
|
||||||
|
|
||||||
proc setupStateDB*(desiredState: JsonNode, stateDB: var AccountStateDB) =
|
proc setupStateDB*(wantedState: JsonNode, stateDB: var AccountStateDB) =
|
||||||
for ac, accountData in desiredState:
|
for ac, accountData in wantedState:
|
||||||
let account = accountFromHex(ac)
|
let account = ethAddressFromHex(ac)
|
||||||
for slot, value in accountData{"storage"}:
|
for slot, value in accountData{"storage"}:
|
||||||
stateDB.setStorage(account, slot.parseInt.u256, value.getInt.u256)
|
stateDB.setStorage(account, slot.parseHexInt.u256, value.getInt.u256)
|
||||||
|
|
||||||
let nonce = accountData{"nonce"}.getInt.u256
|
let nonce = accountData{"nonce"}.getInt.u256
|
||||||
let code = accountData{"code"}.getStr
|
let code = hexToSeqByte(accountData{"code"}.getStr).toRange
|
||||||
let balance = accountData{"balance"}.getInt.u256
|
let balance = accountData{"balance"}.getInt.u256
|
||||||
|
|
||||||
stateDB.setNonce(account, nonce)
|
stateDB.setNonce(account, nonce)
|
||||||
stateDB.setCode(account, code)
|
stateDB.setCode(account, code)
|
||||||
stateDB.setBalance(account, balance)
|
stateDB.setBalance(account, balance)
|
||||||
|
|
||||||
|
proc verifyStateDB*(wantedState: JsonNode, stateDB: AccountStateDB) =
|
||||||
|
for ac, accountData in wantedState:
|
||||||
|
let account = ethAddressFromHex(ac)
|
||||||
|
for slot, value in accountData{"storage"}:
|
||||||
|
let
|
||||||
|
slotId = slot.parseHexInt.u256
|
||||||
|
wantedValue = UInt256.fromHex value.getStr
|
||||||
|
|
||||||
|
let (actualValue, found) = stateDB.getStorage(account, slotId)
|
||||||
|
# echo "FOUND ", found
|
||||||
|
# echo "ACTUAL VALUE ", actualValue.toHex
|
||||||
|
doAssert found and actualValue == wantedValue
|
||||||
|
|
||||||
|
let
|
||||||
|
wantedCode = hexToSeqByte(accountData{"code"}.getStr).toRange
|
||||||
|
wantedBalance = accountData{"balance"}.getInt.u256
|
||||||
|
wantedNonce = accountData{"nonce"}.getInt.u256
|
||||||
|
|
||||||
|
actualCode = stateDB.getCode(account)
|
||||||
|
actualBalance = stateDB.getBalance(account)
|
||||||
|
actualNonce = stateDB.getNonce(account)
|
||||||
|
|
||||||
|
doAssert wantedCode == actualCode
|
||||||
|
doAssert wantedBalance == actualBalance
|
||||||
|
doAssert wantedNonce == actualNonce
|
||||||
|
|
||||||
proc getHexadecimalInt*(j: JsonNode): int =
|
proc getHexadecimalInt*(j: JsonNode): int =
|
||||||
discard parseHex(j.getStr, result)
|
discard parseHex(j.getStr, result)
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import unittest, sequtils,
|
import
|
||||||
stint,
|
unittest, sequtils,
|
||||||
../nimbus/[constants, errors, vm/memory]
|
eth_common/eth_types,
|
||||||
|
../nimbus/[constants, errors, vm/memory]
|
||||||
|
|
||||||
proc memory32: Memory =
|
proc memory32: Memory =
|
||||||
result = newMemory()
|
result = newMemory()
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
unittest, stint, tables, parseutils,
|
unittest, tables, parseutils,
|
||||||
|
eth_trie/[types, memdb], eth_common/eth_types,
|
||||||
../nimbus/[constants, vm_types, logging],
|
../nimbus/[constants, vm_types, logging],
|
||||||
../nimbus/vm/interpreter,
|
../nimbus/vm/interpreter,
|
||||||
../nimbus/utils/header,
|
../nimbus/utils/header,
|
||||||
|
@ -17,7 +18,8 @@ from eth_common import GasInt
|
||||||
|
|
||||||
proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation =
|
proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation =
|
||||||
let header = BlockHeader(blockNumber: blockNum)
|
let header = BlockHeader(blockNumber: blockNum)
|
||||||
var vm = newNimbusVM(header, newBaseChainDB(newMemoryDB()))
|
var memDb = newMemDB()
|
||||||
|
var vm = newNimbusVM(header, newBaseChainDB(trieDB memDb))
|
||||||
# coinbase: "",
|
# coinbase: "",
|
||||||
# difficulty: fixture{"env"}{"currentDifficulty"}.getHexadecimalInt.u256,
|
# difficulty: fixture{"env"}{"currentDifficulty"}.getHexadecimalInt.u256,
|
||||||
# blockNumber: fixture{"env"}{"currentNumber"}.getHexadecimalInt.u256,
|
# blockNumber: fixture{"env"}{"currentNumber"}.getHexadecimalInt.u256,
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import unittest, stint,
|
import
|
||||||
../nimbus/[constants, errors, vm/interpreter, utils/bytes]
|
unittest,
|
||||||
|
eth_common/eth_types,
|
||||||
|
../nimbus/[constants, errors, vm/interpreter, utils/bytes]
|
||||||
|
|
||||||
|
|
||||||
template testPush(value: untyped, expected: untyped): untyped =
|
template testPush(value: untyped, expected: untyped): untyped =
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import
|
import
|
||||||
unittest, macros,
|
unittest, macros,
|
||||||
stint, nimcrypto/[keccak, hash], ranges, eth_common/eth_types,
|
nimcrypto/[keccak, hash], ranges, eth_common/eth_types,
|
||||||
../nimbus/db/[storage_types],
|
../nimbus/db/[storage_types],
|
||||||
../nimbus/db/backends/[sqlite_backend, rocksdb_backend]
|
../nimbus/db/backends/[sqlite_backend, rocksdb_backend]
|
||||||
|
|
||||||
|
|
|
@ -6,51 +6,64 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
unittest, strformat, strutils, sequtils, tables, stint, json, ospaths, times,
|
unittest, strformat, strutils, sequtils, tables, json, ospaths, times,
|
||||||
|
byteutils, ranges/typedranges, nimcrypto/[keccak, hash],
|
||||||
|
rlp, eth_trie/[types, memdb], eth_common,
|
||||||
./test_helpers,
|
./test_helpers,
|
||||||
../nimbus/[constants, errors, logging],
|
../nimbus/[constants, errors, logging],
|
||||||
../nimbus/[vm_state, vm_types],
|
../nimbus/[vm_state, vm_types],
|
||||||
../nimbus/utils/[header, padding],
|
../nimbus/utils/[header, padding],
|
||||||
../nimbus/vm/interpreter,
|
../nimbus/vm/interpreter,
|
||||||
../nimbus/db/[db_chain, state_db, backends/memory_backend],
|
../nimbus/db/[db_chain, state_db, backends/memory_backend]
|
||||||
eth_common
|
|
||||||
|
|
||||||
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
|
||||||
|
|
||||||
suite "vm json tests":
|
suite "vm json tests":
|
||||||
jsonTest("VMTests", testFixture)
|
jsonTest("VMTests", testFixture)
|
||||||
|
|
||||||
|
|
||||||
|
proc stringFromBytes(x: ByteRange): string =
|
||||||
|
result = newString(x.len)
|
||||||
|
for i in 0 ..< x.len:
|
||||||
|
result[i] = char(x[i])
|
||||||
|
|
||||||
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||||
var fixture: JsonNode
|
var fixture: JsonNode
|
||||||
for label, child in fixtures:
|
for label, child in fixtures:
|
||||||
fixture = child
|
fixture = child
|
||||||
break
|
break
|
||||||
let fenv = fixture["env"]
|
let fenv = fixture["env"]
|
||||||
|
var emptyRlpHash = keccak256.digest(rlp.encode("").toOpenArray)
|
||||||
let header = BlockHeader(
|
let header = BlockHeader(
|
||||||
coinbase: fenv{"currentCoinbase"}.getStr.parseAddress,
|
coinbase: fenv{"currentCoinbase"}.getStr.parseAddress,
|
||||||
difficulty: fenv{"currentDifficulty"}.getHexadecimalInt.u256,
|
difficulty: fenv{"currentDifficulty"}.getHexadecimalInt.u256,
|
||||||
blockNumber: fenv{"currentNumber"}.getHexadecimalInt.u256,
|
blockNumber: fenv{"currentNumber"}.getHexadecimalInt.u256,
|
||||||
gasLimit: fenv{"currentGasLimit"}.getHexadecimalInt.GasInt,
|
gasLimit: fenv{"currentGasLimit"}.getHexadecimalInt.GasInt,
|
||||||
timestamp: fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix
|
timestamp: fenv{"currentTimestamp"}.getHexadecimalInt.int64.fromUnix,
|
||||||
|
stateRoot: emptyRlpHash
|
||||||
)
|
)
|
||||||
var vm = newNimbusVM(header, newBaseChainDB(newMemoryDB()))
|
var memDb = newMemDB()
|
||||||
|
var vm = newNimbusVM(header, newBaseChainDB(trieDB memDb))
|
||||||
|
|
||||||
let fexec = fixture["exec"]
|
let fexec = fixture["exec"]
|
||||||
var code = ""
|
var code = ""
|
||||||
vm.state.db(readOnly=false):
|
vm.state.mutateStateDB:
|
||||||
setupStateDB(fixture{"pre"}, db)
|
setupStateDB(fixture{"pre"}, db)
|
||||||
code = db.getCode(fexec{"address"}.getStr.parseAddress)
|
let address = fexec{"address"}.getStr.parseAddress
|
||||||
|
code = stringFromBytes db.getCode(address)
|
||||||
|
|
||||||
code = fexec{"code"}.getStr
|
code = fexec{"code"}.getStr
|
||||||
|
let toAddress = fexec{"address"}.getStr.parseAddress
|
||||||
let message = newMessage(
|
let message = newMessage(
|
||||||
to = fexec{"address"}.getStr.parseAddress,
|
to = toAddress,
|
||||||
sender = fexec{"caller"}.getStr.parseAddress,
|
sender = fexec{"caller"}.getStr.parseAddress,
|
||||||
value = cast[uint](fexec{"value"}.getHexadecimalInt).u256, # Cast workaround for negative value
|
value = cast[uint](fexec{"value"}.getHexadecimalInt).u256, # Cast workaround for negative value
|
||||||
data = fexec{"data"}.getStr.mapIt(it.byte),
|
data = fexec{"data"}.getStr.hexToSeqByte,
|
||||||
code = code,
|
code = code,
|
||||||
gas = fexec{"gas"}.getHexadecimalInt,
|
gas = fexec{"gas"}.getHexadecimalInt,
|
||||||
gasPrice = fexec{"gasPrice"}.getHexadecimalInt,
|
gasPrice = fexec{"gasPrice"}.getHexadecimalInt,
|
||||||
options = newMessageOptions(origin=fexec{"origin"}.getStr.parseAddress))
|
options = newMessageOptions(origin=fexec{"origin"}.getStr.parseAddress,
|
||||||
|
createAddress = toAddress))
|
||||||
|
|
||||||
#echo fixture{"exec"}
|
#echo fixture{"exec"}
|
||||||
var c = newCodeStreamFromUnescaped(code)
|
var c = newCodeStreamFromUnescaped(code)
|
||||||
|
@ -101,7 +114,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||||
for child in zip(computation.children, callCreates):
|
for child in zip(computation.children, callCreates):
|
||||||
var (childComputation, createdCall) = child
|
var (childComputation, createdCall) = child
|
||||||
let toAddress = createdCall{"destination"}.getStr.parseAddress
|
let toAddress = createdCall{"destination"}.getStr.parseAddress
|
||||||
let data = createdCall{"data"}.getStr.mapIt(it.byte)
|
let data = createdCall{"data"}.getStr.hexToSeqByte
|
||||||
let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt
|
let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt
|
||||||
let value = createdCall{"value"}.getHexadecimalInt.u256
|
let value = createdCall{"value"}.getHexadecimalInt.u256
|
||||||
|
|
||||||
|
@ -110,10 +123,11 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||||
check(gasLimit == childComputation.msg.gas)
|
check(gasLimit == childComputation.msg.gas)
|
||||||
check(value == childComputation.msg.value)
|
check(value == childComputation.msg.value)
|
||||||
# TODO postState = fixture{"post"}
|
# TODO postState = fixture{"post"}
|
||||||
|
|
||||||
|
if not fixture{"post"}.isNil:
|
||||||
|
verifyStateDb(fixture{"post"}, computation.vmState.readOnlyStateDB)
|
||||||
else:
|
else:
|
||||||
# Error checks
|
# Error checks
|
||||||
check(computation.isError)
|
check(computation.isError)
|
||||||
# TODO postState = fixture{"pre"}
|
# TODO postState = fixture{"pre"}
|
||||||
|
|
||||||
# TODO with vm.state.stateDb(readOnly=True) as stateDb:
|
|
||||||
# verifyStateDb(postState, stateDb)
|
|
||||||
|
|
Loading…
Reference in New Issue