eip2718: test_blockchain_json pass test
This commit is contained in:
parent
2a9c3982d9
commit
79044f1e92
|
@ -17,11 +17,6 @@ import
|
||||||
json_serialization/lexer
|
json_serialization/lexer
|
||||||
|
|
||||||
type
|
type
|
||||||
# beware that although in some cases
|
|
||||||
# chainId have identical value to networkId
|
|
||||||
# they are separate entity
|
|
||||||
ChainId* = distinct uint
|
|
||||||
|
|
||||||
ChainOptions = object
|
ChainOptions = object
|
||||||
chainId : ChainId
|
chainId : ChainId
|
||||||
homesteadBlock : Option[BlockNumber]
|
homesteadBlock : Option[BlockNumber]
|
||||||
|
|
|
@ -40,9 +40,9 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction,
|
||||||
require=tx.intrinsicGas(fork)
|
require=tx.intrinsicGas(fork)
|
||||||
return
|
return
|
||||||
|
|
||||||
if tx.accountNonce != nonce:
|
if tx.nonce != nonce:
|
||||||
debug "invalid tx: account nonce mismatch",
|
debug "invalid tx: account nonce mismatch",
|
||||||
txNonce=tx.accountnonce,
|
txNonce=tx.nonce,
|
||||||
accountNonce=nonce
|
accountNonce=nonce
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -96,19 +96,30 @@ func logsBloom(logs: openArray[Log]): LogsBloom =
|
||||||
|
|
||||||
func createBloom*(receipts: openArray[Receipt]): Bloom =
|
func createBloom*(receipts: openArray[Receipt]): Bloom =
|
||||||
var bloom: LogsBloom
|
var bloom: LogsBloom
|
||||||
for receipt in receipts:
|
for rec in receipts:
|
||||||
bloom.value = bloom.value or logsBloom(receipt.logs).value
|
bloom.value = bloom.value or logsBloom(rec.logs).value
|
||||||
result = bloom.value.toByteArrayBE
|
result = bloom.value.toByteArrayBE
|
||||||
|
|
||||||
proc makeReceipt*(vmState: BaseVMState, fork = FkFrontier): Receipt =
|
proc makeReceipt*(vmState: BaseVMState, fork: Fork, txType: TxType): Receipt =
|
||||||
if fork < FkByzantium:
|
if txType == AccessListTxType:
|
||||||
result.stateRootOrStatus = hashOrStatus(vmState.accountDb.rootHash)
|
var rec = AccessListReceipt(
|
||||||
else:
|
status: vmState.status,
|
||||||
result.stateRootOrStatus = hashOrStatus(vmState.status)
|
cumulativeGasUsed: vmState.cumulativeGasUsed,
|
||||||
|
logs: vmState.getAndClearLogEntries()
|
||||||
|
)
|
||||||
|
rec.bloom = logsBloom(rec.logs).value.toByteArrayBE
|
||||||
|
return Receipt(receiptType: AccessListReceiptType, accessListReceipt: rec)
|
||||||
|
|
||||||
result.cumulativeGasUsed = vmState.cumulativeGasUsed
|
var rec: LegacyReceipt
|
||||||
result.logs = vmState.getAndClearLogEntries()
|
if fork < FkByzantium:
|
||||||
result.bloom = logsBloom(result.logs).value.toByteArrayBE
|
rec.stateRootOrStatus = hashOrStatus(vmState.accountDb.rootHash)
|
||||||
|
else:
|
||||||
|
rec.stateRootOrStatus = hashOrStatus(vmState.status)
|
||||||
|
|
||||||
|
rec.cumulativeGasUsed = vmState.cumulativeGasUsed
|
||||||
|
rec.logs = vmState.getAndClearLogEntries()
|
||||||
|
rec.bloom = logsBloom(rec.logs).value.toByteArrayBE
|
||||||
|
Receipt(receiptType: LegacyReceiptType, legacyReceipt: rec)
|
||||||
|
|
||||||
func eth(n: int): Uint256 {.compileTime.} =
|
func eth(n: int): Uint256 {.compileTime.} =
|
||||||
n.u256 * pow(10.u256, 18)
|
n.u256 * pow(10.u256, 18)
|
||||||
|
@ -178,7 +189,7 @@ proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, v
|
||||||
else:
|
else:
|
||||||
debug "Could not get sender", txIndex, tx
|
debug "Could not get sender", txIndex, tx
|
||||||
return ValidationResult.Error
|
return ValidationResult.Error
|
||||||
vmState.receipts[txIndex] = makeReceipt(vmState, fork)
|
vmState.receipts[txIndex] = makeReceipt(vmState, fork, tx.txType)
|
||||||
|
|
||||||
if header.ommersHash != EMPTY_UNCLE_HASH:
|
if header.ommersHash != EMPTY_UNCLE_HASH:
|
||||||
let h = chainDB.persistUncles(body.uncles)
|
let h = chainDB.persistUncles(body.uncles)
|
||||||
|
|
|
@ -7,11 +7,30 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
./constants, ./errors, eth/[common, keys], ./utils,
|
./constants, ./errors, eth/[common, keys], ./utils,
|
||||||
|
stew/shims/macros,
|
||||||
./vm_types2, ./vm_gas_costs
|
./vm_types2, ./vm_gas_costs
|
||||||
|
|
||||||
import eth/common/transaction as common_transaction
|
import eth/common/transaction as common_transaction
|
||||||
export common_transaction
|
export common_transaction
|
||||||
|
|
||||||
|
template txc(fn: untyped, params: varargs[untyped]): untyped =
|
||||||
|
if tx.txType == LegacyTxType:
|
||||||
|
unpackArgs(fn, [tx.legacyTx, params])
|
||||||
|
else:
|
||||||
|
unpackArgs(fn, [tx.accessListTx, params])
|
||||||
|
|
||||||
|
template txField(field: untyped): untyped =
|
||||||
|
if tx.txType == LegacyTxType:
|
||||||
|
tx.legacyTx.field
|
||||||
|
else:
|
||||||
|
tx.accessListTx.field
|
||||||
|
|
||||||
|
template txFieldAsgn(field, data: untyped) =
|
||||||
|
if tx.txType == LegacyTxType:
|
||||||
|
tx.legacyTx.field = data
|
||||||
|
else:
|
||||||
|
tx.accessListTx.field = data
|
||||||
|
|
||||||
func intrinsicGas*(data: openarray[byte], fork: Fork): GasInt =
|
func intrinsicGas*(data: openarray[byte], fork: Fork): GasInt =
|
||||||
result = gasFees[fork][GasTransaction]
|
result = gasFees[fork][GasTransaction]
|
||||||
for i in data:
|
for i in data:
|
||||||
|
@ -20,7 +39,7 @@ func intrinsicGas*(data: openarray[byte], fork: Fork): GasInt =
|
||||||
else:
|
else:
|
||||||
result += gasFees[fork][GasTXDataNonZero]
|
result += gasFees[fork][GasTXDataNonZero]
|
||||||
|
|
||||||
proc intrinsicGas*(tx: Transaction, fork: Fork): GasInt =
|
proc intrinsicGas*(tx: TxTypes, fork: Fork): GasInt =
|
||||||
# Compute the baseline gas cost for this transaction. This is the amount
|
# Compute the baseline gas cost for this transaction. This is the amount
|
||||||
# of gas needed to send this transaction (but that is not actually used
|
# of gas needed to send this transaction (but that is not actually used
|
||||||
# for computation)
|
# for computation)
|
||||||
|
@ -29,13 +48,16 @@ proc intrinsicGas*(tx: Transaction, fork: Fork): GasInt =
|
||||||
if tx.isContractCreation:
|
if tx.isContractCreation:
|
||||||
result = result + gasFees[fork][GasTXCreate]
|
result = result + gasFees[fork][GasTXCreate]
|
||||||
|
|
||||||
proc getSignature*(transaction: Transaction, output: var Signature): bool =
|
proc intrinsicGas*(tx: Transaction, fork: Fork): GasInt =
|
||||||
|
txc(intrinsicGas, fork)
|
||||||
|
|
||||||
|
proc getSignature*(tx: LegacyTx, output: var Signature): bool =
|
||||||
var bytes: array[65, byte]
|
var bytes: array[65, byte]
|
||||||
bytes[0..31] = transaction.R.toByteArrayBE()
|
bytes[0..31] = tx.R.toByteArrayBE()
|
||||||
bytes[32..63] = transaction.S.toByteArrayBE()
|
bytes[32..63] = tx.S.toByteArrayBE()
|
||||||
|
|
||||||
# TODO: V will become a byte or range soon.
|
# TODO: V will become a byte or range soon.
|
||||||
var v = transaction.V.int
|
var v = tx.V
|
||||||
if v >= EIP155_CHAIN_ID_OFFSET:
|
if v >= EIP155_CHAIN_ID_OFFSET:
|
||||||
v = 28 - (v and 0x01)
|
v = 28 - (v and 0x01)
|
||||||
elif v == 27 or v == 28:
|
elif v == 27 or v == 28:
|
||||||
|
@ -50,32 +72,76 @@ proc getSignature*(transaction: Transaction, output: var Signature): bool =
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc toSignature*(transaction: Transaction): Signature =
|
proc getSignature*(tx: AccessListTx, output: var Signature): bool =
|
||||||
if not getSignature(transaction, result):
|
var bytes: array[65, byte]
|
||||||
|
bytes[0..31] = tx.R.toByteArrayBE()
|
||||||
|
bytes[32..63] = tx.S.toByteArrayBE()
|
||||||
|
bytes[64] = tx.V.byte
|
||||||
|
let sig = Signature.fromRaw(bytes)
|
||||||
|
if sig.isOk:
|
||||||
|
output = sig[]
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc getSignature*(tx: Transaction, output: var Signature): bool =
|
||||||
|
txc(getSignature, output)
|
||||||
|
|
||||||
|
proc toSignature*(tx: Transaction): Signature =
|
||||||
|
if not getSignature(tx, result):
|
||||||
raise newException(Exception, "Invalid signature")
|
raise newException(Exception, "Invalid signature")
|
||||||
|
|
||||||
proc getSender*(transaction: Transaction, output: var EthAddress): bool =
|
proc getSender*(tx: LegacyTx | AccessListTx | Transaction, output: var EthAddress): bool =
|
||||||
## Find the address the transaction was sent from.
|
## Find the address the transaction was sent from.
|
||||||
var sig: Signature
|
var sig: Signature
|
||||||
if transaction.getSignature(sig):
|
if tx.getSignature(sig):
|
||||||
var txHash = transaction.txHashNoSignature
|
var txHash = tx.txHashNoSignature
|
||||||
let pubkey = recover(sig, SkMessage(txHash.data))
|
let pubkey = recover(sig, SkMessage(txHash.data))
|
||||||
if pubkey.isOk:
|
if pubkey.isOk:
|
||||||
output = pubkey[].toCanonicalAddress()
|
output = pubkey[].toCanonicalAddress()
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc getSender*(transaction: Transaction): EthAddress =
|
proc getSender*(tx: LegacyTx | AccessListTx | Transaction): EthAddress =
|
||||||
## Raises error on failure to recover public key
|
## Raises error on failure to recover public key
|
||||||
if not transaction.getSender(result):
|
if not tx.getSender(result):
|
||||||
raise newException(ValidationError, "Could not derive sender address from transaction")
|
raise newException(ValidationError, "Could not derive sender address from transaction")
|
||||||
|
|
||||||
proc getRecipient*(tx: Transaction, sender: EthAddress): EthAddress =
|
proc getRecipient*(tx: LegacyTx | AccessListTx, sender: EthAddress): EthAddress =
|
||||||
if tx.isContractCreation:
|
if tx.isContractCreation:
|
||||||
result = generateAddress(sender, tx.accountNonce)
|
result = generateAddress(sender, tx.nonce)
|
||||||
else:
|
else:
|
||||||
result = tx.to
|
result = tx.to
|
||||||
|
|
||||||
proc validate*(tx: Transaction, fork: Fork) =
|
proc getRecipient*(tx: Transaction, sender: EthAddress): EthAddress =
|
||||||
|
txc(getRecipient, sender)
|
||||||
|
|
||||||
|
proc gasLimit*(tx: Transaction): GasInt =
|
||||||
|
txField(gasLimit)
|
||||||
|
|
||||||
|
proc gasPrice*(tx: Transaction): GasInt =
|
||||||
|
txField(gasPrice)
|
||||||
|
|
||||||
|
proc value*(tx: Transaction): UInt256 =
|
||||||
|
txField(value)
|
||||||
|
|
||||||
|
proc isContractCreation*(tx: Transaction): bool =
|
||||||
|
txField(isContractCreation)
|
||||||
|
|
||||||
|
proc to*(tx: Transaction): EthAddress =
|
||||||
|
txField(to)
|
||||||
|
|
||||||
|
proc payload*(tx: Transaction): Blob =
|
||||||
|
txField(payload)
|
||||||
|
|
||||||
|
proc nonce*(tx: Transaction): AccountNonce =
|
||||||
|
txField(nonce)
|
||||||
|
|
||||||
|
proc `payload=`*(tx: var Transaction, data: Blob) =
|
||||||
|
txFieldAsgn(payload, data)
|
||||||
|
|
||||||
|
proc `gasLimit=`*(tx: var Transaction, data: GasInt) =
|
||||||
|
txFieldAsgn(gasLimit, data)
|
||||||
|
|
||||||
|
proc validate*(tx: LegacyTx, fork: Fork) =
|
||||||
# Hook called during instantiation to ensure that all transaction
|
# Hook called during instantiation to ensure that all transaction
|
||||||
# parameters pass validation rules
|
# parameters pass validation rules
|
||||||
if tx.intrinsicGas(fork) > tx.gasLimit:
|
if tx.intrinsicGas(fork) > tx.gasLimit:
|
||||||
|
@ -87,18 +153,18 @@ proc validate*(tx: Transaction, fork: Fork) =
|
||||||
raise newException(ValidationError, "Invalid signature or failed message verification")
|
raise newException(ValidationError, "Invalid signature or failed message verification")
|
||||||
|
|
||||||
var
|
var
|
||||||
vMin = 27
|
vMin = 27'i64
|
||||||
vMax = 28
|
vMax = 28'i64
|
||||||
|
|
||||||
if tx.V.int >= EIP155_CHAIN_ID_OFFSET:
|
if tx.V >= EIP155_CHAIN_ID_OFFSET:
|
||||||
let chainId = (tx.V.int - EIP155_CHAIN_ID_OFFSET) div 2
|
let chainId = (tx.V - EIP155_CHAIN_ID_OFFSET) div 2
|
||||||
vMin = 35 + (2 * chainId)
|
vMin = 35 + (2 * chainId)
|
||||||
vMax = vMin + 1
|
vMax = vMin + 1
|
||||||
|
|
||||||
var isValid = tx.R >= Uint256.one
|
var isValid = tx.R >= Uint256.one
|
||||||
isValid = isValid and tx.S >= Uint256.one
|
isValid = isValid and tx.S >= Uint256.one
|
||||||
isValid = isValid and tx.V.int >= vMin
|
isValid = isValid and tx.V >= vMin
|
||||||
isValid = isValid and tx.V.int <= vMax
|
isValid = isValid and tx.V <= vMax
|
||||||
isValid = isValid and tx.S < SECPK1_N
|
isValid = isValid and tx.S < SECPK1_N
|
||||||
isValid = isValid and tx.R < SECPK1_N
|
isValid = isValid and tx.R < SECPK1_N
|
||||||
|
|
||||||
|
@ -107,4 +173,3 @@ proc validate*(tx: Transaction, fork: Fork) =
|
||||||
|
|
||||||
if not isValid:
|
if not isValid:
|
||||||
raise newException(ValidationError, "Invalid transaction")
|
raise newException(ValidationError, "Invalid transaction")
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ proc asmSetupComputation(tx: Transaction, sender: EthAddress, vmState: BaseVMSta
|
||||||
forkOverride = forkOverride,
|
forkOverride = forkOverride,
|
||||||
)
|
)
|
||||||
|
|
||||||
let contractAddress = generateAddress(sender, tx.accountNonce)
|
let contractAddress = generateAddress(sender, tx.nonce)
|
||||||
let msg = Message(
|
let msg = Message(
|
||||||
kind: evmcCall,
|
kind: evmcCall,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
|
|
|
@ -535,7 +535,7 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
|
||||||
Number: fixed GasBase,
|
Number: fixed GasBase,
|
||||||
Difficulty: fixed GasBase,
|
Difficulty: fixed GasBase,
|
||||||
GasLimit: fixed GasBase,
|
GasLimit: fixed GasBase,
|
||||||
ChainID: fixed GasBase,
|
ChainIdOp: fixed GasBase,
|
||||||
SelfBalance: fixed GasLow,
|
SelfBalance: fixed GasLow,
|
||||||
|
|
||||||
# 50s: Stack, Memory, Storage and Flow Operations
|
# 50s: Stack, Memory, Storage and Flow Operations
|
||||||
|
|
|
@ -79,7 +79,7 @@ fill_enum_holes:
|
||||||
Difficulty = 0x44, # Get the block's difficulty.
|
Difficulty = 0x44, # Get the block's difficulty.
|
||||||
GasLimit = 0x45, # Get the block's gas limit.
|
GasLimit = 0x45, # Get the block's gas limit.
|
||||||
|
|
||||||
ChainId = 0x46, # Get current chain’s EIP-155 unique identifier.
|
ChainIdOp = 0x46, # Get current chain’s EIP-155 unique identifier.
|
||||||
SelfBalance = 0x47, # Get current contract's balance.
|
SelfBalance = 0x47, # Get current contract's balance.
|
||||||
|
|
||||||
# 50s: Stack, Memory, Storage and Flow Operations
|
# 50s: Stack, Memory, Storage and Flow Operations
|
||||||
|
|
|
@ -223,7 +223,7 @@ let PetersburgOpDispatch {.compileTime.}: array[Op, NimNode] = genPetersburgJump
|
||||||
|
|
||||||
proc genIstanbulJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compileTime.} =
|
proc genIstanbulJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compileTime.} =
|
||||||
result = ops
|
result = ops
|
||||||
result[ChainId] = newIdentNode "chainId"
|
result[ChainIdOp] = newIdentNode "chainId"
|
||||||
result[SelfBalance] = newIdentNode "selfBalance"
|
result[SelfBalance] = newIdentNode "selfBalance"
|
||||||
result[SStore] = newIdentNode "sstoreEIP2200"
|
result[SStore] = newIdentNode "sstoreEIP2200"
|
||||||
|
|
||||||
|
|
|
@ -81,23 +81,25 @@ proc parseBlockHeader*(n: JsonNode): BlockHeader =
|
||||||
n.fromJson "nonce", result.nonce
|
n.fromJson "nonce", result.nonce
|
||||||
|
|
||||||
proc parseTransaction*(n: JsonNode): Transaction =
|
proc parseTransaction*(n: JsonNode): Transaction =
|
||||||
n.fromJson "nonce", result.accountNonce
|
var tx: LegacyTx
|
||||||
n.fromJson "gasPrice", result.gasPrice
|
n.fromJson "nonce", tx.nonce
|
||||||
n.fromJson "gas", result.gasLimit
|
n.fromJson "gasPrice", tx.gasPrice
|
||||||
|
n.fromJson "gas", tx.gasLimit
|
||||||
|
|
||||||
result.isContractCreation = n["to"].kind == JNull
|
tx.isContractCreation = n["to"].kind == JNull
|
||||||
if not result.isContractCreation:
|
if not tx.isContractCreation:
|
||||||
n.fromJson "to", result.to
|
n.fromJson "to", tx.to
|
||||||
|
|
||||||
n.fromJson "value", result.value
|
n.fromJson "value", tx.value
|
||||||
n.fromJson "input", result.payload
|
n.fromJson "input", tx.payload
|
||||||
n.fromJson "v", result.V
|
n.fromJson "v", tx.V
|
||||||
n.fromJson "r", result.R
|
n.fromJson "r", tx.R
|
||||||
n.fromJson "s", result.S
|
n.fromJson "s", tx.S
|
||||||
|
|
||||||
var sender = result.getSender()
|
var sender = tx.getSender()
|
||||||
doAssert sender.prefixHex == n["from"].getStr()
|
doAssert sender.prefixHex == n["from"].getStr()
|
||||||
doAssert n["hash"].getStr() == result.rlpHash().prefixHex
|
doAssert n["hash"].getStr() == tx.rlpHash().prefixHex
|
||||||
|
result = Transaction(txType: LegacyTxType, legacyTx: tx)
|
||||||
|
|
||||||
proc parseLog(n: JsonNode): Log =
|
proc parseLog(n: JsonNode): Log =
|
||||||
n.fromJson "address", result.address
|
n.fromJson "address", result.address
|
||||||
|
@ -118,18 +120,20 @@ proc parseLogs(n: JsonNode): seq[Log] =
|
||||||
result = @[]
|
result = @[]
|
||||||
|
|
||||||
proc parseReceipt*(n: JsonNode): Receipt =
|
proc parseReceipt*(n: JsonNode): Receipt =
|
||||||
|
var rec: LegacyReceipt
|
||||||
if n.hasKey("root"):
|
if n.hasKey("root"):
|
||||||
var hash: Hash256
|
var hash: Hash256
|
||||||
n.fromJson "root", hash
|
n.fromJson "root", hash
|
||||||
result.stateRootOrStatus = hashOrStatus(hash)
|
rec.stateRootOrStatus = hashOrStatus(hash)
|
||||||
else:
|
else:
|
||||||
var status: int
|
var status: int
|
||||||
n.fromJson "status", status
|
n.fromJson "status", status
|
||||||
result.stateRootOrStatus = hashOrStatus(status == 1)
|
rec.stateRootOrStatus = hashOrStatus(status == 1)
|
||||||
|
|
||||||
n.fromJson "cumulativeGasUsed", result.cumulativeGasUsed
|
n.fromJson "cumulativeGasUsed", rec.cumulativeGasUsed
|
||||||
n.fromJson "logsBloom", result.bloom
|
n.fromJson "logsBloom", rec.bloom
|
||||||
result.logs = parseLogs(n["logs"])
|
rec.logs = parseLogs(n["logs"])
|
||||||
|
Receipt(receiptType: LegacyReceiptType, legacyReceipt: rec)
|
||||||
|
|
||||||
proc headerHash*(n: JsonNode): Hash256 =
|
proc headerHash*(n: JsonNode): Hash256 =
|
||||||
n.fromJson "hash", result
|
n.fromJson "hash", result
|
||||||
|
|
|
@ -525,7 +525,7 @@ proc runTester(tester: var Tester, chainDB: BaseChainDB, testStatusIMPL: var Tes
|
||||||
try:
|
try:
|
||||||
let (_, _, _) = tester.applyFixtureBlockToChain(testBlock,
|
let (_, _, _) = tester.applyFixtureBlockToChain(testBlock,
|
||||||
chainDB, checkSeal, validation = true, testStatusIMPL)
|
chainDB, checkSeal, validation = true, testStatusIMPL)
|
||||||
except ValueError, ValidationError, BlockNotFound, MalformedRlpError, RlpTypeMismatch:
|
except ValueError, ValidationError, BlockNotFound, RlpError:
|
||||||
# failure is expected on this bad block
|
# failure is expected on this bad block
|
||||||
check (testBlock.hasException or (not testBlock.goodBlock))
|
check (testBlock.hasException or (not testBlock.goodBlock))
|
||||||
noError = false
|
noError = false
|
||||||
|
@ -601,7 +601,7 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
|
||||||
var success = true
|
var success = true
|
||||||
try:
|
try:
|
||||||
tester.runTester(chainDB, testStatusIMPL)
|
tester.runTester(chainDB, testStatusIMPL)
|
||||||
|
success = testStatusIMPL == OK
|
||||||
let latestBlockHash = chainDB.getCanonicalHead().blockHash
|
let latestBlockHash = chainDB.getCanonicalHead().blockHash
|
||||||
if latestBlockHash != tester.lastBlockHash:
|
if latestBlockHash != tester.lastBlockHash:
|
||||||
verifyStateDB(fixture["postState"], tester.vmState.readOnlyStateDB)
|
verifyStateDB(fixture["postState"], tester.vmState.readOnlyStateDB)
|
||||||
|
|
|
@ -184,32 +184,91 @@ proc verifyStateDB*(wantedState: JsonNode, stateDB: ReadOnlyStateDB) =
|
||||||
if wantedNonce != actualNonce:
|
if wantedNonce != actualNonce:
|
||||||
raise newException(ValidationError, &"{ac} nonceDiff {wantedNonce.toHex} != {actualNonce.toHex}")
|
raise newException(ValidationError, &"{ac} nonceDiff {wantedNonce.toHex} != {actualNonce.toHex}")
|
||||||
|
|
||||||
|
proc parseAccessList(n: JsonNode): AccessList =
|
||||||
|
if n.kind == JNull:
|
||||||
|
return
|
||||||
|
|
||||||
|
for x in n:
|
||||||
|
var ap = AccessPair(
|
||||||
|
address: parseAddress(x["address"].getStr)
|
||||||
|
)
|
||||||
|
let sks = x["storageKeys"]
|
||||||
|
for sk in sks:
|
||||||
|
ap.storageKeys.add hexToByteArray[32](sk.getStr())
|
||||||
|
result.add ap
|
||||||
|
|
||||||
|
proc signTx(tx: var LegacyTx, privateKey: PrivateKey) =
|
||||||
|
let sig = sign(privateKey, tx.rlpEncode)
|
||||||
|
let raw = sig.toRaw()
|
||||||
|
tx.R = fromBytesBE(Uint256, raw[0..31])
|
||||||
|
tx.S = fromBytesBE(Uint256, raw[32..63])
|
||||||
|
tx.V = raw[64].int64 + 27
|
||||||
|
|
||||||
|
proc signTx(tx: var AccessListTx, privateKey: PrivateKey) =
|
||||||
|
let sig = sign(privateKey, tx.rlpEncode)
|
||||||
|
let raw = sig.toRaw()
|
||||||
|
tx.R = fromBytesBE(Uint256, raw[0..31])
|
||||||
|
tx.S = fromBytesBE(Uint256, raw[32..63])
|
||||||
|
tx.V = raw[64].int64
|
||||||
|
|
||||||
proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction =
|
proc getFixtureTransaction*(j: JsonNode, dataIndex, gasIndex, valueIndex: int): Transaction =
|
||||||
result.accountNonce = j["nonce"].getHexadecimalInt.AccountNonce
|
let nonce = j["nonce"].getHexadecimalInt.AccountNonce
|
||||||
result.gasPrice = j["gasPrice"].getHexadecimalInt
|
let gasPrice = j["gasPrice"].getHexadecimalInt
|
||||||
result.gasLimit = j["gasLimit"][gasIndex].getHexadecimalInt
|
let gasLimit = j["gasLimit"][gasIndex].getHexadecimalInt
|
||||||
|
|
||||||
|
var toAddr: EthAddress
|
||||||
|
var contract: bool
|
||||||
|
|
||||||
# TODO: there are a couple fixtures which appear to distinguish between
|
# TODO: there are a couple fixtures which appear to distinguish between
|
||||||
# empty and 0 transaction.to; check/verify whether correct conditions.
|
# empty and 0 transaction.to; check/verify whether correct conditions.
|
||||||
let rawTo = j["to"].getStr
|
let rawTo = j["to"].getStr
|
||||||
if rawTo == "":
|
if rawTo == "":
|
||||||
result.to = "0x".parseAddress
|
toAddr = "0x".parseAddress
|
||||||
result.isContractCreation = true
|
contract = true
|
||||||
else:
|
else:
|
||||||
result.to = rawTo.parseAddress
|
toAddr = rawTo.parseAddress
|
||||||
result.isContractCreation = false
|
contract = false
|
||||||
result.value = fromHex(UInt256, j["value"][valueIndex].getStr)
|
|
||||||
result.payload = j["data"][dataIndex].getStr.safeHexToSeqByte
|
let value = fromHex(UInt256, j["value"][valueIndex].getStr)
|
||||||
|
let payload = j["data"][dataIndex].getStr.safeHexToSeqByte
|
||||||
|
|
||||||
var secretKey = j["secretKey"].getStr
|
var secretKey = j["secretKey"].getStr
|
||||||
removePrefix(secretKey, "0x")
|
removePrefix(secretKey, "0x")
|
||||||
let privateKey = PrivateKey.fromHex(secretKey).tryGet()
|
let privateKey = PrivateKey.fromHex(secretKey).tryGet()
|
||||||
let sig = sign(privateKey, result.rlpEncode)
|
|
||||||
let raw = sig.toRaw()
|
|
||||||
|
|
||||||
result.R = fromBytesBE(Uint256, raw[0..31])
|
if j.hasKey("accessLists"):
|
||||||
result.S = fromBytesBE(Uint256, raw[32..63])
|
let accList = j["accessLists"][dataIndex]
|
||||||
result.V = raw[64] + 27.byte
|
var tx = AccessListTx(
|
||||||
|
nonce: nonce,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
gasLimit: gasLimit,
|
||||||
|
to: toAddr,
|
||||||
|
isContractCreation: contract,
|
||||||
|
value: value,
|
||||||
|
payload: payload,
|
||||||
|
accessList: parseAccessList(accList),
|
||||||
|
chainId: common.ChainId(1)
|
||||||
|
)
|
||||||
|
signTx(tx, privateKey)
|
||||||
|
Transaction(
|
||||||
|
txType: AccessListTxType,
|
||||||
|
accessListTx: tx
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
var tx = LegacyTx(
|
||||||
|
nonce: nonce,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
gasLimit: gasLimit,
|
||||||
|
to: toAddr,
|
||||||
|
isContractCreation: contract,
|
||||||
|
value: value,
|
||||||
|
payload: payload
|
||||||
|
)
|
||||||
|
signTx(tx, privateKey)
|
||||||
|
Transaction(
|
||||||
|
txType: LegacyTxType,
|
||||||
|
legacyTx: tx
|
||||||
|
)
|
||||||
|
|
||||||
proc hashLogEntries*(logs: seq[Log]): string =
|
proc hashLogEntries*(logs: seq[Log]): string =
|
||||||
toLowerAscii("0x" & $keccakHash(rlp.encode(logs)))
|
toLowerAscii("0x" & $keccakHash(rlp.encode(logs)))
|
||||||
|
|
Loading…
Reference in New Issue