mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 12:54:13 +00:00
setup block and state env for more complex eth rpc tests
This commit is contained in:
parent
d089a61539
commit
c9802edfce
@ -132,7 +132,8 @@ proc addBlockNumberToHashLookup*(self: BaseChainDB; header: BlockHeader) =
|
||||
self.db.put(blockNumberToHashKey(header.blockNumber).toOpenArray,
|
||||
rlp.encode(header.hash))
|
||||
|
||||
proc persistTransactions*(self: BaseChainDB, blockNumber: BlockNumber, transactions: openArray[Transaction]) =
|
||||
proc persistTransactions*(self: BaseChainDB, blockNumber:
|
||||
BlockNumber, transactions: openArray[Transaction]): Hash256 =
|
||||
var trie = initHexaryTrie(self.db)
|
||||
for idx, tx in transactions:
|
||||
let
|
||||
@ -141,6 +142,7 @@ proc persistTransactions*(self: BaseChainDB, blockNumber: BlockNumber, transacti
|
||||
txKey: TransactionKey = (blockNumber, idx)
|
||||
trie.put(rlp.encode(idx), encodedTx)
|
||||
self.db.put(transactionHashToBlockKey(txHash).toOpenArray, rlp.encode(txKey))
|
||||
trie.rootHash
|
||||
|
||||
iterator getBlockTransactionData*(self: BaseChainDB, transactionRoot: Hash256): seq[byte] =
|
||||
var transactionDb = initHexaryTrie(self.db, transactionRoot)
|
||||
@ -245,10 +247,11 @@ proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
||||
## Returns True if the header with the given block hash is in our DB.
|
||||
self.db.contains(genericHashKey(blockHash).toOpenArray)
|
||||
|
||||
proc persistReceipts*(self: BaseChainDB, receipts: openArray[Receipt]) =
|
||||
proc persistReceipts*(self: BaseChainDB, receipts: openArray[Receipt]): Hash256 =
|
||||
var trie = initHexaryTrie(self.db)
|
||||
for idx, rec in receipts:
|
||||
trie.put(rlp.encode(idx), rlp.encode(rec))
|
||||
trie.rootHash
|
||||
|
||||
iterator getReceipts*(self: BaseChainDB; header: BlockHeader): Receipt =
|
||||
var receiptDb = initHexaryTrie(self.db, header.receiptRoot)
|
||||
|
@ -152,8 +152,8 @@ method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarr
|
||||
debug "Stored block header hash doesn't match declared hash"
|
||||
return ValidationResult.Error
|
||||
|
||||
c.db.persistTransactions(headers[i].blockNumber, bodies[i].transactions)
|
||||
c.db.persistReceipts(vmState.receipts)
|
||||
discard c.db.persistTransactions(headers[i].blockNumber, bodies[i].transactions)
|
||||
discard c.db.persistReceipts(vmState.receipts)
|
||||
|
||||
# update currentBlock *after* we persist it
|
||||
# so the rpc return consistent result
|
||||
|
@ -37,7 +37,7 @@ type
|
||||
gas*: Option[HexQuantityStr] # (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.
|
||||
gasPrice*: Option[HexQuantityStr]# (optional) Integer of the gasPrice used for each paid gas.
|
||||
value*: Option[HexQuantityStr] # (optional) Integer of the value sent with this transaction.
|
||||
data*: Option[HexDataStr] # (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
data*: Option[EthHashStr] # (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI.
|
||||
|
||||
## A block object, or null when no block was found
|
||||
## Note that this includes slightly different information from eth/common.BlockHeader
|
||||
|
@ -15,13 +15,13 @@ import hexstrings, eth/[common, rlp, keys], stew/byteutils, nimcrypto,
|
||||
|
||||
type
|
||||
UnsignedTx* = object
|
||||
nonce : AccountNonce
|
||||
gasPrice: GasInt
|
||||
gasLimit: GasInt
|
||||
to {.rlpCustomSerialization.}: EthAddress
|
||||
value : UInt256
|
||||
payload : Blob
|
||||
contractCreation {.rlpIgnore.}: bool
|
||||
nonce* : AccountNonce
|
||||
gasPrice*: GasInt
|
||||
gasLimit*: GasInt
|
||||
to* {.rlpCustomSerialization.}: EthAddress
|
||||
value * : UInt256
|
||||
payload* : Blob
|
||||
contractCreation* {.rlpIgnore.}: bool
|
||||
|
||||
CallData* = object
|
||||
source: EthAddress
|
||||
@ -202,13 +202,17 @@ proc setupComputation(vmState: BaseVMState, call: CallData, fork: Fork) : Comput
|
||||
|
||||
result = newComputation(vmState, msg)
|
||||
|
||||
import json
|
||||
|
||||
proc doCall*(call: CallData, header: BlockHeader, chain: BaseChainDB): HexDataStr =
|
||||
var
|
||||
# we use current header stateRoot, unlike block validation
|
||||
# which use previous block stateRoot
|
||||
vmState = newBaseVMState(header.stateRoot, header, chain)
|
||||
vmState = newBaseVMState(header.stateRoot, header, chain, {EnableTracing})
|
||||
fork = toFork(chain.config, header.blockNumber)
|
||||
comp = setupComputation(vmState, call, fork)
|
||||
|
||||
comp.execComputation()
|
||||
result = hexDataStr(comp.returnData)
|
||||
result = hexDataStr(comp.output)
|
||||
# TODO: handle revert and error
|
||||
# TODO: handle contract ABI
|
||||
|
@ -136,6 +136,8 @@ proc generateContractAddress(c: Computation, salt: Uint256): EthAddress =
|
||||
else:
|
||||
result = generateSafeAddress(c.msg.sender, salt, c.msg.data)
|
||||
|
||||
import stew/byteutils
|
||||
|
||||
proc newComputation*(vmState: BaseVMState, message: Message, salt= 0.u256): Computation =
|
||||
new result
|
||||
result.vmState = vmState
|
||||
|
@ -7,14 +7,14 @@
|
||||
|
||||
import
|
||||
unittest, json, strformat, strutils, options, tables, os,
|
||||
nimcrypto, stew/byteutils,
|
||||
nimcrypto, stew/byteutils, times,
|
||||
json_rpc/[rpcserver, rpcclient], eth/common as eth_common,
|
||||
eth/[rlp, keys], eth/trie/db, eth/p2p/rlpx_protocols/eth_protocol,
|
||||
../nimbus/rpc/[common, p2p, hexstrings, rpc_types],
|
||||
../nimbus/rpc/[common, p2p, hexstrings, rpc_types, rpc_utils],
|
||||
../nimbus/[constants, vm_state, config, genesis, utils, transaction],
|
||||
../nimbus/db/[accounts_cache, db_chain, storage_types],
|
||||
../nimbus/p2p/chain,
|
||||
./rpcclient/test_hexstrings, ./test_helpers
|
||||
../nimbus/db/[accounts_cache, db_chain, storage_types, state_db],
|
||||
../nimbus/p2p/[chain, executor], ../nimbus/utils/difficulty,
|
||||
./rpcclient/test_hexstrings, ./test_helpers, ./macro_assembler
|
||||
|
||||
from eth/p2p/rlpx_protocols/whisper_protocol import SymKey
|
||||
|
||||
@ -30,27 +30,93 @@ template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
|
||||
const sigPath = &"{sourceDir}{DirSep}rpcclient{DirSep}ethcallsigs.nim"
|
||||
createRpcSigs(RpcSocketClient, sigPath)
|
||||
|
||||
proc setupEnv(chain: BaseChainDB, signer, ks2: EthAddress, conf: NimbusConfiguration) =
|
||||
var
|
||||
parent = chain.getCanonicalHead()
|
||||
ac = newAccountStateDB(chain.db, parent.stateRoot, chain.pruneTrie)
|
||||
acc = conf.getAccount(signer).tryGet()
|
||||
blockNumber = 1.toBlockNumber
|
||||
parentHash = parent.blockHash
|
||||
fork = chain.config.toFork(blockNumber)
|
||||
|
||||
const code = evmByteCode:
|
||||
PUSH4 "0xDEADBEEF" # PUSH
|
||||
PUSH1 "0x00" # MSTORE AT 0x00
|
||||
MSTORE
|
||||
PUSH1 "0x04" # RETURN LEN
|
||||
PUSH1 "0x1C" # RETURN OFFSET at 28
|
||||
RETURN
|
||||
|
||||
ac.setCode(ks2, code)
|
||||
ac.addBalance(signer, 1_000_000.u256)
|
||||
var vmState = newBaseVMState(ac.rootHash, BlockHeader(parentHash: parentHash), chain)
|
||||
|
||||
let
|
||||
unsignedTx1 = UnsignedTx(
|
||||
nonce : 0,
|
||||
gasPrice: 1_100,
|
||||
gasLimit: 70_000,
|
||||
value : 1.u256,
|
||||
contractCreation: false
|
||||
)
|
||||
unsignedTx2 = UnsignedTx(
|
||||
nonce : 0,
|
||||
gasPrice: 1_200,
|
||||
gasLimit: 70_000,
|
||||
value : 2.u256,
|
||||
contractCreation: false
|
||||
)
|
||||
signedTx1 = signTransaction(unsignedTx1, chain, acc.privateKey)
|
||||
signedTx2 = signTransaction(unsignedTx2, chain, acc.privateKey)
|
||||
txs = [signedTx1, signedTx2]
|
||||
txRoot = chain.persistTransactions(blockNumber, txs)
|
||||
|
||||
vmState.receipts = newSeq[Receipt](txs.len)
|
||||
vmState.cumulativeGasUsed = 0
|
||||
for txIndex, tx in txs:
|
||||
let sender = tx.getSender()
|
||||
discard processTransaction(tx, sender, vmState, fork)
|
||||
vmState.receipts[txIndex] = makeReceipt(vmState, fork)
|
||||
|
||||
let
|
||||
receiptRoot = chain.persistReceipts(vmState.receipts)
|
||||
date = initDateTime(30, mMar, 2017, 00, 00, 00, 00, utc())
|
||||
timeStamp = date.toTime
|
||||
difficulty = calcDifficulty(chain.config, timeStamp, parent)
|
||||
|
||||
let header = BlockHeader(
|
||||
parentHash : parentHash,
|
||||
#ommersHash*: Hash256
|
||||
#coinbase*: EthAddress
|
||||
stateRoot : vmState.accountDb.rootHash,
|
||||
txRoot : txRoot,
|
||||
receiptRoot : receiptRoot,
|
||||
bloom : createBloom(vmState.receipts),
|
||||
difficulty : difficulty,
|
||||
blockNumber : blockNumber,
|
||||
gasLimit : vmState.cumulativeGasUsed + 1000,
|
||||
gasUsed : vmState.cumulativeGasUsed,
|
||||
timestamp : timeStamp
|
||||
#extraData: Blob
|
||||
#mixDigest: Hash256
|
||||
#nonce: BlockNonce
|
||||
)
|
||||
|
||||
discard chain.persistHeaderToDb(header)
|
||||
|
||||
proc doTests {.async.} =
|
||||
# TODO: Include other transports such as Http
|
||||
var ethNode = setupEthNode(eth)
|
||||
let
|
||||
emptyRlpHash = keccak256.digest(rlp.encode(""))
|
||||
header = BlockHeader(stateRoot: emptyRlpHash)
|
||||
var
|
||||
ethNode = setupEthNode(eth)
|
||||
chain = newBaseChainDB(newMemoryDb())
|
||||
state = newBaseVMState(emptyRlpHash, header, chain)
|
||||
ethNode.chain = newChain(chain)
|
||||
|
||||
let
|
||||
balance = 100.u256
|
||||
address: EthAddress = hexToByteArray[20]("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
|
||||
|
||||
signer: EthAddress = hexToByteArray[20]("0x0e69cde81b1aa07a45c32c6cd85d67229d36bb1b")
|
||||
ks2: EthAddress = hexToByteArray[20]("0xa3b2222afa5c987da6ef773fde8d01b9f23d481f")
|
||||
ks3: EthAddress = hexToByteArray[20]("0x597176e9a64aad0845d83afdaf698fbeff77703b")
|
||||
|
||||
conf = getConfiguration()
|
||||
|
||||
ethNode.chain = newChain(chain)
|
||||
conf.keyStore = "tests" / "keystore"
|
||||
let res = conf.loadKeystoreFiles()
|
||||
if res.isErr:
|
||||
@ -64,9 +130,8 @@ proc doTests {.async.} =
|
||||
doAssert(unlock.isOk)
|
||||
|
||||
defaultGenesisBlockForNetwork(conf.net.networkId.toPublicNetwork()).commit(chain)
|
||||
state.mutateStateDB:
|
||||
db.setBalance(address, balance)
|
||||
doAssert(canonicalHeadHashKey().toOpenArray in state.chainDb.db)
|
||||
doAssert(canonicalHeadHashKey().toOpenArray in chain.db)
|
||||
setupEnv(chain, signer, ks2, conf)
|
||||
|
||||
# Create Ethereum RPCs
|
||||
let RPC_PORT = 8545
|
||||
@ -144,9 +209,7 @@ proc doTests {.async.} =
|
||||
|
||||
test "eth_gasPrice":
|
||||
let res = await client.eth_gasPrice()
|
||||
# genesis block doesn't have any transaction
|
||||
# to generate meaningful prices
|
||||
check res.string == "0x0"
|
||||
check res.string == "0x47E"
|
||||
|
||||
test "eth_accounts":
|
||||
let res = await client.eth_accounts()
|
||||
@ -156,7 +219,7 @@ proc doTests {.async.} =
|
||||
|
||||
test "eth_blockNumber":
|
||||
let res = await client.eth_blockNumber()
|
||||
check res.string == "0x0"
|
||||
check res.string == "0x1"
|
||||
|
||||
test "eth_getBalance":
|
||||
let a = await client.eth_getBalance(ethAddressStr("0xfff33a3bd36abdbd412707b8e310d6011454a7ae"), "0x0")
|
||||
@ -240,11 +303,11 @@ proc doTests {.async.} =
|
||||
to: ethAddressStr(ks2).some,
|
||||
gas: encodeQuantity(100000'u).some,
|
||||
gasPrice: none(HexQuantityStr),
|
||||
value: encodeQuantity(100'u).some,
|
||||
data: HexDataStr("0x").some,
|
||||
value: encodeQuantity(100'u).some
|
||||
)
|
||||
|
||||
let res = await client.eth_call(ec, "latest")
|
||||
check hexToByteArray[4](res.string) == hexToByteArray[4]("deadbeef")
|
||||
|
||||
#test "eth_estimateGas":
|
||||
# let
|
||||
|
Loading…
x
Reference in New Issue
Block a user