Migrate to Engine API spec version v1.0.0-alpha.5; More progress towards working M1
This commit is contained in:
parent
990846135a
commit
3cbb920406
|
@ -62,6 +62,9 @@ if not defined(macosx):
|
||||||
# light-weight stack traces using libbacktrace and libunwind
|
# light-weight stack traces using libbacktrace and libunwind
|
||||||
--define:nimStackTraceOverride
|
--define:nimStackTraceOverride
|
||||||
switch("import", "libbacktrace")
|
switch("import", "libbacktrace")
|
||||||
|
else:
|
||||||
|
--stacktrace:on
|
||||||
|
--linetrace:on
|
||||||
|
|
||||||
--define:nimOldCaseObjects # https://github.com/status-im/nim-confutils/issues/9
|
--define:nimOldCaseObjects # https://github.com/status-im/nim-confutils/issues/9
|
||||||
# libnimbus.so needs position-independent code
|
# libnimbus.so needs position-independent code
|
||||||
|
|
|
@ -103,6 +103,7 @@ const
|
||||||
defaultEthWsPort = 8546
|
defaultEthWsPort = 8546
|
||||||
defaultEthGraphqlPort = 8547
|
defaultEthGraphqlPort = 8547
|
||||||
defaultEngineApiPort = 8550
|
defaultEngineApiPort = 8550
|
||||||
|
defaultEngineApiWsPort = 8551
|
||||||
defaultListenAddress = (static ValidIpAddress.init("0.0.0.0"))
|
defaultListenAddress = (static ValidIpAddress.init("0.0.0.0"))
|
||||||
defaultAdminListenAddress = (static ValidIpAddress.init("127.0.0.1"))
|
defaultAdminListenAddress = (static ValidIpAddress.init("127.0.0.1"))
|
||||||
defaultListenAddressDesc = $defaultListenAddress & ", meaning all network interfaces"
|
defaultListenAddressDesc = $defaultListenAddress & ", meaning all network interfaces"
|
||||||
|
@ -328,6 +329,23 @@ type
|
||||||
defaultValueDesc: defaultAdminListenAddressDesc
|
defaultValueDesc: defaultAdminListenAddressDesc
|
||||||
name: "engine-api-address" .}: ValidIpAddress
|
name: "engine-api-address" .}: ValidIpAddress
|
||||||
|
|
||||||
|
engineApiWsEnabled* {.
|
||||||
|
desc: "Enable the WebSocket Engine API"
|
||||||
|
defaultValue: false
|
||||||
|
name: "engine-api-ws" .}: bool
|
||||||
|
|
||||||
|
engineApiWsPort* {.
|
||||||
|
desc: "Listening port for the WebSocket Engine API"
|
||||||
|
defaultValue: defaultEngineApiWsPort
|
||||||
|
defaultValueDesc: $defaultEngineApiWsPort
|
||||||
|
name: "engine-api-ws-port" .}: Port
|
||||||
|
|
||||||
|
engineApiWsAddress* {.
|
||||||
|
desc: "Listening address for the WebSocket Engine API"
|
||||||
|
defaultValue: defaultAdminListenAddress
|
||||||
|
defaultValueDesc: defaultAdminListenAddressDesc
|
||||||
|
name: "engine-api-ws-address" .}: ValidIpAddress
|
||||||
|
|
||||||
nodeKeyHex* {.
|
nodeKeyHex* {.
|
||||||
desc: "P2P node private key (as 32 bytes hex string)"
|
desc: "P2P node private key (as 32 bytes hex string)"
|
||||||
defaultValue: ""
|
defaultValue: ""
|
||||||
|
|
|
@ -40,6 +40,7 @@ type
|
||||||
NimbusNode = ref object
|
NimbusNode = ref object
|
||||||
rpcServer: RpcHttpServer
|
rpcServer: RpcHttpServer
|
||||||
engineApiServer: RpcHttpServer
|
engineApiServer: RpcHttpServer
|
||||||
|
engineApiWsServer: RpcWebSocketServer
|
||||||
ethNode: EthereumNode
|
ethNode: EthereumNode
|
||||||
state: NimbusState
|
state: NimbusState
|
||||||
graphqlServer: GraphqlHttpServerRef
|
graphqlServer: GraphqlHttpServerRef
|
||||||
|
@ -157,7 +158,8 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
|
|
||||||
# Enable RPC APIs based on RPC flags and protocol flags
|
# Enable RPC APIs based on RPC flags and protocol flags
|
||||||
let rpcFlags = conf.getRpcFlags()
|
let rpcFlags = conf.getRpcFlags()
|
||||||
if RpcFlag.Eth in rpcFlags and ProtocolFlag.Eth in protocols:
|
if (RpcFlag.Eth in rpcFlags and ProtocolFlag.Eth in protocols) or
|
||||||
|
(conf.engineApiPort == conf.rpcPort):
|
||||||
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.rpcServer)
|
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.rpcServer)
|
||||||
if RpcFlag.Debug in rpcFlags:
|
if RpcFlag.Debug in rpcFlags:
|
||||||
setupDebugRpc(chainDB, nimbus.rpcServer)
|
setupDebugRpc(chainDB, nimbus.rpcServer)
|
||||||
|
@ -176,7 +178,8 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
|
|
||||||
# Enable Websocket RPC APIs based on RPC flags and protocol flags
|
# Enable Websocket RPC APIs based on RPC flags and protocol flags
|
||||||
let wsFlags = conf.getWsFlags()
|
let wsFlags = conf.getWsFlags()
|
||||||
if RpcFlag.Eth in wsFlags and ProtocolFlag.Eth in protocols:
|
if (RpcFlag.Eth in wsFlags and ProtocolFlag.Eth in protocols) or
|
||||||
|
(conf.engineApiWsPort == conf.wsPort):
|
||||||
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.wsRpcServer)
|
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.wsRpcServer)
|
||||||
if RpcFlag.Debug in wsFlags:
|
if RpcFlag.Debug in wsFlags:
|
||||||
setupDebugRpc(chainDB, nimbus.wsRpcServer)
|
setupDebugRpc(chainDB, nimbus.wsRpcServer)
|
||||||
|
@ -219,13 +222,30 @@ proc localServices(nimbus: NimbusNode, conf: NimbusConf,
|
||||||
nimbus.sealingEngine.start()
|
nimbus.sealingEngine.start()
|
||||||
|
|
||||||
if conf.engineApiEnabled:
|
if conf.engineApiEnabled:
|
||||||
|
if conf.engineApiPort != conf.rpcPort:
|
||||||
nimbus.engineApiServer = newRpcHttpServer([
|
nimbus.engineApiServer = newRpcHttpServer([
|
||||||
initTAddress(conf.engineApiAddress, conf.engineApiPort)
|
initTAddress(conf.engineApiAddress, conf.engineApiPort)
|
||||||
])
|
])
|
||||||
setupEngineAPI(nimbus.sealingEngine, nimbus.engineApiServer)
|
setupEngineAPI(nimbus.sealingEngine, nimbus.engineApiServer)
|
||||||
nimbus.engineAPiServer.start()
|
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.engineApiServer)
|
||||||
|
nimbus.engineApiServer.start()
|
||||||
|
else:
|
||||||
|
setupEngineAPI(nimbus.sealingEngine, nimbus.rpcServer)
|
||||||
|
|
||||||
info "Starting engine API server", port = conf.engineApiPort
|
info "Starting engine API server", port = conf.engineApiPort
|
||||||
|
|
||||||
|
if conf.engineApiWsEnabled:
|
||||||
|
if conf.engineApiWsPort != conf.wsPort:
|
||||||
|
nimbus.engineApiWsServer = newRpcWebSocketServer(
|
||||||
|
initTAddress(conf.engineApiWsAddress, conf.engineApiWsPort))
|
||||||
|
setupEngineAPI(nimbus.sealingEngine, nimbus.engineApiWsServer)
|
||||||
|
setupEthRpc(nimbus.ethNode, nimbus.ctx, chainDB, nimbus.txPool, nimbus.engineApiWsServer)
|
||||||
|
nimbus.engineApiWsServer.start()
|
||||||
|
else:
|
||||||
|
setupEngineAPI(nimbus.sealingEngine, nimbus.wsRpcServer)
|
||||||
|
|
||||||
|
info "Starting WebSocket engine API server", port = conf.engineApiWsPort
|
||||||
|
|
||||||
# metrics server
|
# metrics server
|
||||||
if conf.metricsEnabled:
|
if conf.metricsEnabled:
|
||||||
info "Starting metrics HTTP server", address = conf.metricsAddress, port = conf.metricsPort
|
info "Starting metrics HTTP server", address = conf.metricsAddress, port = conf.metricsPort
|
||||||
|
@ -283,6 +303,8 @@ proc stop*(nimbus: NimbusNode, conf: NimbusConf) {.async, gcsafe.} =
|
||||||
await nimbus.engineAPiServer.stop()
|
await nimbus.engineAPiServer.stop()
|
||||||
if conf.wsEnabled:
|
if conf.wsEnabled:
|
||||||
nimbus.wsRpcServer.stop()
|
nimbus.wsRpcServer.stop()
|
||||||
|
if conf.engineApiWsEnabled:
|
||||||
|
nimbus.engineApiWsServer.stop()
|
||||||
if conf.graphqlEnabled:
|
if conf.graphqlEnabled:
|
||||||
await nimbus.graphqlServer.stop()
|
await nimbus.graphqlServer.stop()
|
||||||
if conf.engineSigner != ZERO_ADDRESS:
|
if conf.engineSigner != ZERO_ADDRESS:
|
||||||
|
|
|
@ -80,8 +80,9 @@ func toNextFork(n: BlockNumber): uint64 =
|
||||||
else:
|
else:
|
||||||
result = n.truncate(uint64)
|
result = n.truncate(uint64)
|
||||||
|
|
||||||
func isBlockAfterTtd*(c: Chain, blockNum: BlockNumber): bool =
|
func isBlockAfterTtd*(c: Chain, blockHeader: BlockHeader): bool =
|
||||||
c.ttdReachedAt.isSome and blockNum > c.ttdReachedAt.get
|
# TODO: This should be fork aware
|
||||||
|
c.ttdReachedAt.isSome and blockHeader.blockNumber > c.ttdReachedAt.get
|
||||||
|
|
||||||
func getNextFork(c: ChainConfig, fork: ChainFork): uint64 =
|
func getNextFork(c: ChainConfig, fork: ChainFork): uint64 =
|
||||||
let next: array[ChainFork, uint64] = [
|
let next: array[ChainFork, uint64] = [
|
||||||
|
|
|
@ -74,7 +74,8 @@ proc persistBlocksImpl(c: Chain; headers: openarray[BlockHeader];
|
||||||
return validationResult
|
return validationResult
|
||||||
|
|
||||||
if c.extraValidation and c.verifyFrom <= header.blockNumber:
|
if c.extraValidation and c.verifyFrom <= header.blockNumber:
|
||||||
if c.db.config.poaEngine:
|
let isBlockAfterTtd = c.isBlockAfterTtd(header)
|
||||||
|
if c.db.config.poaEngine and not isBlockAfterTtd:
|
||||||
var parent = if 0 < i: @[headers[i-1]] else: @[]
|
var parent = if 0 < i: @[headers[i-1]] else: @[]
|
||||||
let rc = c.clique.cliqueVerify(header,parent)
|
let rc = c.clique.cliqueVerify(header,parent)
|
||||||
if rc.isOK:
|
if rc.isOK:
|
||||||
|
@ -90,7 +91,7 @@ proc persistBlocksImpl(c: Chain; headers: openarray[BlockHeader];
|
||||||
header,
|
header,
|
||||||
body,
|
body,
|
||||||
checkSealOK = false, # TODO: how to checkseal from here
|
checkSealOK = false, # TODO: how to checkseal from here
|
||||||
ttdReached = c.isBlockAfterTtd(header.blockNumber),
|
ttdReached = isBlockAfterTtd,
|
||||||
pow = c.pow)
|
pow = c.pow)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
debug "block validation error",
|
debug "block validation error",
|
||||||
|
|
|
@ -34,7 +34,7 @@ export
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
const
|
const
|
||||||
daoForkBlockExtraData =
|
daoForkBlockExtraData* =
|
||||||
byteutils.hexToByteArray[13](DAOForkBlockExtra).toSeq
|
byteutils.hexToByteArray[13](DAOForkBlockExtra).toSeq
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -40,7 +40,7 @@ proc calcRootHashRlp*(items: openArray[seq[byte]]): Hash256 =
|
||||||
tr.put(rlp.encode(i), t)
|
tr.put(rlp.encode(i), t)
|
||||||
return tr.rootHash()
|
return tr.rootHash()
|
||||||
|
|
||||||
proc toBlockHeader(payload: ExecutionPayload): eth_types.BlockHeader =
|
proc toBlockHeader(payload: ExecutionPayloadV1): eth_types.BlockHeader =
|
||||||
discard payload.random # TODO: What should this be used for?
|
discard payload.random # TODO: What should this be used for?
|
||||||
|
|
||||||
let transactions = seq[seq[byte]](payload.transactions)
|
let transactions = seq[seq[byte]](payload.transactions)
|
||||||
|
@ -49,10 +49,10 @@ proc toBlockHeader(payload: ExecutionPayload): eth_types.BlockHeader =
|
||||||
EthBlockHeader(
|
EthBlockHeader(
|
||||||
parentHash : payload.parentHash.asEthHash,
|
parentHash : payload.parentHash.asEthHash,
|
||||||
ommersHash : EMPTY_UNCLE_HASH,
|
ommersHash : EMPTY_UNCLE_HASH,
|
||||||
coinbase : EthAddress payload.coinbase,
|
coinbase : EthAddress payload.feeRecipient,
|
||||||
stateRoot : payload.stateRoot.asEthHash,
|
stateRoot : payload.stateRoot.asEthHash,
|
||||||
txRoot : txRoot,
|
txRoot : txRoot,
|
||||||
receiptRoot : payload.receiptRoot.asEthHash,
|
receiptRoot : payload.receiptsRoot.asEthHash,
|
||||||
bloom : distinctBase(payload.logsBloom),
|
bloom : distinctBase(payload.logsBloom),
|
||||||
difficulty : default(DifficultyInt),
|
difficulty : default(DifficultyInt),
|
||||||
blockNumber : payload.blockNumber.distinctBase.u256,
|
blockNumber : payload.blockNumber.distinctBase.u256,
|
||||||
|
@ -65,40 +65,53 @@ proc toBlockHeader(payload: ExecutionPayload): eth_types.BlockHeader =
|
||||||
fee : some payload.baseFeePerGas
|
fee : some payload.baseFeePerGas
|
||||||
)
|
)
|
||||||
|
|
||||||
proc toBlockBody(payload: ExecutionPayload): BlockBody =
|
proc toBlockBody(payload: ExecutionPayloadV1): BlockBody =
|
||||||
# TODO the transactions from the payload have to be converted here
|
# TODO the transactions from the payload have to be converted here
|
||||||
discard payload.transactions
|
discard payload.transactions
|
||||||
|
|
||||||
proc setupEngineAPI*(sealingEngine: SealingEngineRef, server: RpcServer) =
|
proc setupEngineAPI*(
|
||||||
|
sealingEngine: SealingEngineRef,
|
||||||
|
server: RpcServer) =
|
||||||
|
|
||||||
var payloadsInstance = newClone(newSeq[ExecutionPayload]())
|
var payloadsInstance = newClone(newSeq[ExecutionPayloadV1]())
|
||||||
template payloads: auto = payloadsInstance[]
|
template payloads: auto = payloadsInstance[]
|
||||||
|
|
||||||
server.rpc("engine_getPayload") do(payloadId: Quantity) -> ExecutionPayload:
|
# https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.5/src/engine/specification.md#engine_getpayloadv1
|
||||||
if payloadId.uint64 > high(int).uint64 or
|
server.rpc("engine_getPayloadV1") do(payloadIdBytes: FixedBytes[8]) -> ExecutionPayloadV1:
|
||||||
int(payloadId) >= payloads.len:
|
let payloadId = uint64.fromBytesBE(distinctBase payloadIdBytes)
|
||||||
raise (ref InvalidRequest)(code: UNKNOWN_PAYLOAD, msg: "Unknown payload")
|
if payloadId > payloads.len.uint64:
|
||||||
|
raise (ref InvalidRequest)(code: engineApiUnknownPayload, msg: "Unknown payload")
|
||||||
return payloads[int payloadId]
|
return payloads[int payloadId]
|
||||||
|
|
||||||
server.rpc("engine_executePayload") do(payload: ExecutionPayload) -> ExecutePayloadResponse:
|
# https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.5/src/engine/specification.md#engine_executepayloadv1
|
||||||
|
server.rpc("engine_executePayloadV1") do(payload: ExecutionPayloadV1) -> ExecutePayloadResponse:
|
||||||
# TODO
|
# TODO
|
||||||
if payload.transactions.len > 0:
|
if payload.transactions.len > 0:
|
||||||
# Give us a break, a block with transcations? instructions to execute?
|
# Give us a break, a block with transcations? instructions to execute?
|
||||||
# Nah, we are syncing!
|
# Nah, we are syncing!
|
||||||
return ExecutePayloadResponse(status: $PayloadExecutionStatus.syncing)
|
return ExecutePayloadResponse(status: PayloadExecutionStatus.syncing)
|
||||||
|
|
||||||
|
# TODO check whether we are syncing
|
||||||
|
|
||||||
let
|
let
|
||||||
headers = [payload.toBlockHeader]
|
headers = [payload.toBlockHeader]
|
||||||
bodies = [payload.toBlockBody]
|
bodies = [payload.toBlockBody]
|
||||||
|
|
||||||
if rlpHash(headers[0]) != payload.blockHash.asEthHash:
|
if rlpHash(headers[0]) != payload.blockHash.asEthHash:
|
||||||
return ExecutePayloadResponse(status: $PayloadExecutionStatus.invalid)
|
return ExecutePayloadResponse(status: PayloadExecutionStatus.invalid,
|
||||||
|
validationError: some "payload root doesn't match its contents")
|
||||||
|
|
||||||
if sealingEngine.chain.persistBlocks(headers, bodies) != ValidationResult.OK:
|
if sealingEngine.chain.persistBlocks(headers, bodies) != ValidationResult.OK:
|
||||||
return ExecutePayloadResponse(status: $PayloadExecutionStatus.invalid)
|
# TODO Provide validationError and latestValidHash
|
||||||
|
return ExecutePayloadResponse(status: PayloadExecutionStatus.invalid)
|
||||||
|
|
||||||
return ExecutePayloadResponse(status: $PayloadExecutionStatus.valid)
|
return ExecutePayloadResponse(status: PayloadExecutionStatus.valid,
|
||||||
|
latestValidHash: some payload.blockHash)
|
||||||
|
|
||||||
server.rpc("engine_forkchoiceUpdated") do(update: ForkChoiceUpdate):
|
# https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.5/src/engine/specification.md#engine_forkchoiceupdatedv1
|
||||||
|
server.rpc("engine_forkchoiceUpdatedV1") do(
|
||||||
|
update: ForkchoiceStateV1,
|
||||||
|
payloadAttributes: Option[PayloadAttributesV1]) -> ForkchoiceUpdatedResponse:
|
||||||
let
|
let
|
||||||
db = sealingEngine.chain.db
|
db = sealingEngine.chain.db
|
||||||
newHead = update.headBlockHash.asEthHash
|
newHead = update.headBlockHash.asEthHash
|
||||||
|
@ -107,5 +120,24 @@ proc setupEngineAPI*(sealingEngine: SealingEngineRef, server: RpcServer) =
|
||||||
# histories that are no longer relevant
|
# histories that are no longer relevant
|
||||||
discard update.finalizedBlockHash
|
discard update.finalizedBlockHash
|
||||||
|
|
||||||
|
# TODO Check whether we are syncing
|
||||||
|
|
||||||
if not db.setHead(newHead):
|
if not db.setHead(newHead):
|
||||||
raise (ref InvalidRequest)(code: UNKNOWN_HEADER, msg: "Uknown head block hash")
|
return ForkchoiceUpdatedResponse(status: ForkchoiceUpdatedStatus.syncing)
|
||||||
|
|
||||||
|
if payloadAttributes.isSome:
|
||||||
|
let payloadId = uint64 payloads.len
|
||||||
|
|
||||||
|
var payload: ExecutionPayloadV1
|
||||||
|
let generatePayloadRes = sealingEngine.generateExecutionPayload(
|
||||||
|
payloadAttributes.get,
|
||||||
|
payload)
|
||||||
|
if generatePayloadRes.isErr:
|
||||||
|
raise newException(CatchableError, generatePayloadRes.error)
|
||||||
|
|
||||||
|
payloads.add payload
|
||||||
|
|
||||||
|
return ForkchoiceUpdatedResponse(status: ForkchoiceUpdatedStatus.success,
|
||||||
|
payloadId: some payloadId.toBytesBE.PayloadID)
|
||||||
|
else:
|
||||||
|
return ForkchoiceUpdatedResponse(status: ForkchoiceUpdatedStatus.success)
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
]#
|
]#
|
||||||
|
|
||||||
import
|
import
|
||||||
stint, stew/byteutils, eth/[keys, rlp], eth/common/eth_types
|
stint, stew/byteutils, eth/[keys, rlp],
|
||||||
|
eth/common/eth_types,
|
||||||
|
json_serialization
|
||||||
|
|
||||||
type
|
type
|
||||||
HexQuantityStr* = distinct string
|
HexQuantityStr* = distinct string
|
||||||
|
@ -300,3 +302,15 @@ proc fromJson*(n: JsonNode, argName: string, result: var Hash256) =
|
||||||
|
|
||||||
proc fromJson*(n: JsonNode, argName: string, result: var JsonNode) =
|
proc fromJson*(n: JsonNode, argName: string, result: var JsonNode) =
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter, value: HexQuantityStr) =
|
||||||
|
writeValue(writer, string value)
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter, value: HexDataStr) =
|
||||||
|
writeValue(writer, string value)
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter, value: EthAddressStr) =
|
||||||
|
writeValue(writer, string value)
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter, value: EthHashStr) =
|
||||||
|
writeValue(writer, string value)
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
times, options, tables,
|
times, tables,
|
||||||
json_rpc/rpcserver, hexstrings, stint, stew/byteutils,
|
json_rpc/rpcserver, hexstrings, stint, stew/byteutils,
|
||||||
|
json_serialization, web3/conversions, json_serialization/std/options,
|
||||||
|
eth/common/eth_types_json_serialization,
|
||||||
eth/[common, keys, rlp, p2p], nimcrypto,
|
eth/[common, keys, rlp, p2p], nimcrypto,
|
||||||
".."/[transaction, vm_state, constants, utils, context],
|
".."/[transaction, vm_state, constants, utils, context],
|
||||||
../db/[db_chain, state_db],
|
../db/[db_chain, state_db],
|
||||||
|
@ -297,7 +299,9 @@ proc setupEthRpc*(node: EthereumNode, ctx: EthContext, chain: BaseChainDB, txPoo
|
||||||
hash = data.toHash
|
hash = data.toHash
|
||||||
|
|
||||||
if chain.getBlockHeader(hash, header):
|
if chain.getBlockHeader(hash, header):
|
||||||
result = some(populateBlockObject(header, chain, fullTransactions))
|
result = some populateBlockObject(header, chain, fullTransactions)
|
||||||
|
else:
|
||||||
|
result = none BlockObject
|
||||||
|
|
||||||
server.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> Option[BlockObject]:
|
server.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> Option[BlockObject]:
|
||||||
## Returns information about a block by block number.
|
## Returns information about a block by block number.
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import
|
import
|
||||||
hexstrings, options, eth/[common, keys, rlp], json
|
hexstrings, options, eth/[common, keys, rlp], json
|
||||||
|
|
||||||
|
from
|
||||||
|
web3/ethtypes import FixedBytes
|
||||||
|
|
||||||
|
export FixedBytes
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Notes:
|
Notes:
|
||||||
* Some of the types suppose 'null' when there is no appropriate value.
|
* Some of the types suppose 'null' when there is no appropriate value.
|
||||||
|
@ -49,7 +54,7 @@ type
|
||||||
parentHash*: Hash256 # hash of the parent block.
|
parentHash*: Hash256 # hash of the parent block.
|
||||||
nonce*: Option[HexDataStr] # hash of the generated proof-of-work. null when its pending block.
|
nonce*: Option[HexDataStr] # hash of the generated proof-of-work. null when its pending block.
|
||||||
sha3Uncles*: Hash256 # SHA3 of the uncles data in the block.
|
sha3Uncles*: Hash256 # SHA3 of the uncles data in the block.
|
||||||
logsBloom*: Option[BloomFilter] # the bloom filter for the logs of the block. null when its pending block.
|
logsBloom*: FixedBytes[256] # the bloom filter for the logs of the block. null when its pending block.
|
||||||
transactionsRoot*: Hash256 # the root of the transaction trie of the block.
|
transactionsRoot*: Hash256 # the root of the transaction trie of the block.
|
||||||
stateRoot*: Hash256 # the root of the final state trie of the block.
|
stateRoot*: Hash256 # the root of the final state trie of the block.
|
||||||
receiptsRoot*: Hash256 # the root of the receipts trie of the block.
|
receiptsRoot*: Hash256 # the root of the receipts trie of the block.
|
||||||
|
@ -107,7 +112,7 @@ type
|
||||||
gasUsed*: HexQuantityStr # the amount of gas used by this specific transaction alone.
|
gasUsed*: HexQuantityStr # the amount of gas used by this specific transaction alone.
|
||||||
contractAddress*: Option[EthAddress] # the contract address created, if the transaction was a contract creation, otherwise null.
|
contractAddress*: Option[EthAddress] # the contract address created, if the transaction was a contract creation, otherwise null.
|
||||||
logs*: seq[Log] # list of log objects which this transaction generated.
|
logs*: seq[Log] # list of log objects which this transaction generated.
|
||||||
logsBloom*: BloomFilter # bloom filter for light clients to quickly retrieve related logs.
|
logsBloom*: FixedBytes[256] # bloom filter for light clients to quickly retrieve related logs.
|
||||||
root*: Option[Hash256] # post-transaction stateroot (pre Byzantium).
|
root*: Option[Hash256] # post-transaction stateroot (pre Byzantium).
|
||||||
status*: Option[int] # 1 = success, 0 = failure.
|
status*: Option[int] # 1 = success, 0 = failure.
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ proc populateBlockObject*(header: BlockHeader, chain: BaseChainDB, fullTx: bool,
|
||||||
result.parentHash = header.parentHash
|
result.parentHash = header.parentHash
|
||||||
result.nonce = some(hexDataStr(header.nonce))
|
result.nonce = some(hexDataStr(header.nonce))
|
||||||
result.sha3Uncles = header.ommersHash
|
result.sha3Uncles = header.ommersHash
|
||||||
result.logsBloom = some(header.bloom)
|
result.logsBloom = FixedBytes[256] header.bloom
|
||||||
result.transactionsRoot = header.txRoot
|
result.transactionsRoot = header.txRoot
|
||||||
result.stateRoot = header.stateRoot
|
result.stateRoot = header.stateRoot
|
||||||
result.receiptsRoot = header.receiptRoot
|
result.receiptsRoot = header.receiptRoot
|
||||||
|
@ -183,7 +183,7 @@ proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction, txInde
|
||||||
result.contractAddress = some(contractAddress)
|
result.contractAddress = some(contractAddress)
|
||||||
|
|
||||||
result.logs = receipt.logs
|
result.logs = receipt.logs
|
||||||
result.logsBloom = receipt.bloom
|
result.logsBloom = FixedBytes[256] receipt.bloom
|
||||||
|
|
||||||
# post-transaction stateroot (pre Byzantium).
|
# post-transaction stateroot (pre Byzantium).
|
||||||
if receipt.hasStateRoot:
|
if receipt.hasStateRoot:
|
||||||
|
|
|
@ -16,12 +16,12 @@ import
|
||||||
clique_desc,
|
clique_desc,
|
||||||
clique_cfg,
|
clique_cfg,
|
||||||
clique_sealer],
|
clique_sealer],
|
||||||
./p2p/gaslimit,
|
./p2p/[gaslimit, validate],
|
||||||
"."/[chain_config, utils, context],
|
"."/[chain_config, utils, context],
|
||||||
"."/utils/tx_pool
|
"."/utils/tx_pool
|
||||||
|
|
||||||
from web3/ethtypes as web3types import nil
|
from web3/ethtypes as web3types import nil
|
||||||
from web3/engine_api_types import ExecutionPayload, PayloadAttributes
|
from web3/engine_api_types import ExecutionPayloadV1, PayloadAttributesV1
|
||||||
|
|
||||||
type
|
type
|
||||||
EngineState* = enum
|
EngineState* = enum
|
||||||
|
@ -85,8 +85,7 @@ proc prepareHeader(engine: SealingEngineRef,
|
||||||
parent.gasLimit,
|
parent.gasLimit,
|
||||||
gasFloor = DEFAULT_GAS_LIMIT,
|
gasFloor = DEFAULT_GAS_LIMIT,
|
||||||
gasCeil = DEFAULT_GAS_LIMIT),
|
gasCeil = DEFAULT_GAS_LIMIT),
|
||||||
# TODO: extraData can be configured via cli
|
extraData : daoForkBlockExtraData,
|
||||||
#extraData : engine.extra,
|
|
||||||
coinbase : coinbase,
|
coinbase : coinbase,
|
||||||
timestamp : timestamp,
|
timestamp : timestamp,
|
||||||
ommersHash : EMPTY_UNCLE_HASH,
|
ommersHash : EMPTY_UNCLE_HASH,
|
||||||
|
@ -106,30 +105,29 @@ proc prepareHeader(engine: SealingEngineRef,
|
||||||
# TODO: desiredLimit can be configured by user, gasCeil
|
# TODO: desiredLimit can be configured by user, gasCeil
|
||||||
header.gasLimit = calcGasLimit1559(parentGasLimit, desiredLimit = DEFAULT_GAS_LIMIT)
|
header.gasLimit = calcGasLimit1559(parentGasLimit, desiredLimit = DEFAULT_GAS_LIMIT)
|
||||||
|
|
||||||
# TODO Post merge, clique should not be executing
|
if engine.chain.isBlockAfterTtd(header):
|
||||||
let clique = engine.chain.clique
|
header.difficulty = DifficultyInt.zero
|
||||||
let res = clique.prepare(parent, header)
|
header.mixDigest = default(Hash256)
|
||||||
|
header.nonce = default(BlockNonce)
|
||||||
|
else:
|
||||||
|
let res = engine.chain.clique.prepare(parent, header)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
return err($res.error)
|
return err($res.error)
|
||||||
|
|
||||||
if engine.chain.isBlockAfterTtd(header.blockNumber):
|
|
||||||
header.difficulty = DifficultyInt.zero
|
|
||||||
|
|
||||||
ok(header)
|
ok(header)
|
||||||
|
|
||||||
proc generateBlock(engine: SealingEngineRef,
|
proc generateBlock(engine: SealingEngineRef,
|
||||||
coinbase: EthAddress,
|
coinbase: EthAddress,
|
||||||
parentBlockHeader: BlockHeader,
|
parentBlockHeader: BlockHeader,
|
||||||
outBlock: var EthBlock): Result[void, string] =
|
outBlock: var EthBlock,
|
||||||
|
timestamp = getTime()): Result[void, string] =
|
||||||
# deviation from standard block generator
|
# deviation from standard block generator
|
||||||
# - no local and remote transactions inclusion(need tx pool)
|
# - no local and remote transactions inclusion(need tx pool)
|
||||||
# - no receipts from tx
|
# - no receipts from tx
|
||||||
# - no DAO hard fork
|
# - no DAO hard fork
|
||||||
# - no local and remote uncles inclusion
|
# - no local and remote uncles inclusion
|
||||||
|
|
||||||
let clique = engine.chain.clique
|
let res = prepareHeader(engine, coinbase, parentBlockHeader, timestamp)
|
||||||
let time = getTime()
|
|
||||||
let res = prepareHeader(engine, coinbase, parentBlockHeader, time)
|
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
return err("error prepare header")
|
return err("error prepare header")
|
||||||
|
|
||||||
|
@ -137,8 +135,9 @@ proc generateBlock(engine: SealingEngineRef,
|
||||||
header: res.get()
|
header: res.get()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not engine.chain.isBlockAfterTtd(outBlock.header):
|
||||||
# TODO Post merge, Clique should not be executing
|
# TODO Post merge, Clique should not be executing
|
||||||
let sealRes = clique.seal(outBlock)
|
let sealRes = engine.chain.clique.seal(outBlock)
|
||||||
if sealRes.isErr:
|
if sealRes.isErr:
|
||||||
return err("error sealing block header: " & $sealRes.error)
|
return err("error sealing block header: " & $sealRes.error)
|
||||||
|
|
||||||
|
@ -151,10 +150,11 @@ proc generateBlock(engine: SealingEngineRef,
|
||||||
proc generateBlock(engine: SealingEngineRef,
|
proc generateBlock(engine: SealingEngineRef,
|
||||||
coinbase: EthAddress,
|
coinbase: EthAddress,
|
||||||
parentHash: Hash256,
|
parentHash: Hash256,
|
||||||
outBlock: var EthBlock): Result[void, string] =
|
outBlock: var EthBlock,
|
||||||
|
timestamp = getTime()): Result[void, string] =
|
||||||
var parentBlockHeader: BlockHeader
|
var parentBlockHeader: BlockHeader
|
||||||
if engine.chain.db.getBlockHeader(parentHash, parentBlockHeader):
|
if engine.chain.db.getBlockHeader(parentHash, parentBlockHeader):
|
||||||
generateBlock(engine, coinbase, parentBlockHeader, outBlock)
|
generateBlock(engine, coinbase, parentBlockHeader, outBlock, timestamp)
|
||||||
else:
|
else:
|
||||||
# TODO:
|
# TODO:
|
||||||
# This hack shouldn't be necessary if the database can find
|
# This hack shouldn't be necessary if the database can find
|
||||||
|
@ -167,8 +167,10 @@ proc generateBlock(engine: SealingEngineRef,
|
||||||
|
|
||||||
proc generateBlock(engine: SealingEngineRef,
|
proc generateBlock(engine: SealingEngineRef,
|
||||||
coinbase: EthAddress,
|
coinbase: EthAddress,
|
||||||
outBlock: var EthBlock): Result[void, string] =
|
outBlock: var EthBlock,
|
||||||
generateBlock(engine, coinbase, engine.chain.currentBlock(), outBlock)
|
timestamp = getTime()): Result[void, string] =
|
||||||
|
generateBlock(engine, coinbase, engine.chain.currentBlock(),
|
||||||
|
outBlock, timestamp)
|
||||||
|
|
||||||
proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
|
proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
|
||||||
let clique = engine.chain.clique
|
let clique = engine.chain.clique
|
||||||
|
@ -217,13 +219,22 @@ proc sealingLoop(engine: SealingEngineRef): Future[void] {.async.} =
|
||||||
|
|
||||||
info "block generated", number=blk.header.blockNumber
|
info "block generated", number=blk.header.blockNumber
|
||||||
|
|
||||||
|
template unsafeQuantityToInt64(q: web3types.Quantity): int64 =
|
||||||
|
int64 q
|
||||||
|
|
||||||
proc generateExecutionPayload*(engine: SealingEngineRef,
|
proc generateExecutionPayload*(engine: SealingEngineRef,
|
||||||
payloadAttrs: PayloadAttributes,
|
payloadAttrs: PayloadAttributesV1,
|
||||||
payloadRes: var ExecutionPayload): Result[void, string] =
|
payloadRes: var ExecutionPayloadV1): Result[void, string] =
|
||||||
|
let headBlock = try: engine.chain.db.getCanonicalHead()
|
||||||
|
except CatchableError: return err "No head block in database"
|
||||||
|
|
||||||
var blk: EthBlock
|
var blk: EthBlock
|
||||||
let blkRes = engine.generateBlock(EthAddress payloadAttrs.feeRecipient,
|
let blkRes = engine.generateBlock(
|
||||||
payloadAttrs.parentHash.asEthHash,
|
EthAddress payloadAttrs.suggestedFeeRecipient,
|
||||||
blk)
|
headBlock,
|
||||||
|
blk,
|
||||||
|
fromUnix(payloadAttrs.timestamp.unsafeQuantityToInt64))
|
||||||
|
|
||||||
if blkRes.isErr:
|
if blkRes.isErr:
|
||||||
error "sealing engine generateBlock error", msg = blkRes.error
|
error "sealing engine generateBlock error", msg = blkRes.error
|
||||||
return blkRes
|
return blkRes
|
||||||
|
@ -233,10 +244,12 @@ proc generateExecutionPayload*(engine: SealingEngineRef,
|
||||||
])
|
])
|
||||||
|
|
||||||
payloadRes.parentHash = Web3BlockHash blk.header.parentHash.data
|
payloadRes.parentHash = Web3BlockHash blk.header.parentHash.data
|
||||||
payloadRes.coinbase = Web3Address blk.header.coinbase
|
payloadRes.feeRecipient = Web3Address blk.header.coinbase
|
||||||
payloadRes.stateRoot = Web3BlockHash blk.header.stateRoot.data
|
payloadRes.stateRoot = Web3BlockHash blk.header.stateRoot.data
|
||||||
payloadRes.receiptRoot = Web3BlockHash blk.header.receiptRoot.data
|
payloadRes.receiptsRoot = Web3BlockHash blk.header.receiptRoot.data
|
||||||
payloadRes.logsBloom = Web3Bloom blk.header.bloom
|
payloadRes.logsBloom = Web3Bloom blk.header.bloom
|
||||||
|
# TODO Check the extra data length here
|
||||||
|
# payloadres.extraData = web3types.DynamicBytes[256] blk.header.extraData
|
||||||
payloadRes.random = web3types.FixedBytes[32](payloadAttrs.random)
|
payloadRes.random = web3types.FixedBytes[32](payloadAttrs.random)
|
||||||
payloadRes.blockNumber = Web3Quantity blk.header.blockNumber.truncate(uint64)
|
payloadRes.blockNumber = Web3Quantity blk.header.blockNumber.truncate(uint64)
|
||||||
payloadRes.gasLimit = Web3Quantity blk.header.gasLimit
|
payloadRes.gasLimit = Web3Quantity blk.header.gasLimit
|
||||||
|
|
|
@ -13,20 +13,20 @@ set -Eeuo pipefail
|
||||||
# eth/catalyst: fix random in payload, payloadid as hexutil
|
# eth/catalyst: fix random in payload, payloadid as hexutil
|
||||||
|
|
||||||
# Get the payload
|
# Get the payload
|
||||||
resp_get_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_getPayload","params":["0x0"],"id":67}' http://localhost:8550)
|
resp_get_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_getPayloadV1","params":["0x0"],"id":67}' http://localhost:8550)
|
||||||
echo "engine_getPayload response: ${resp_get_payload}"
|
echo "engine_getPayloadV1 response: ${resp_get_payload}"
|
||||||
|
|
||||||
expected_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}'
|
expected_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}'
|
||||||
empirical_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0x7a694c5e6e372e6f865b073c101c2fba01f899f16480eb13f7e333a3b7e015bc","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}'
|
empirical_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"blockHash":"0x7a694c5e6e372e6f865b073c101c2fba01f899f16480eb13f7e333a3b7e015bc","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0x0000000000000000000000000000000000000000","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x989680","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}}'
|
||||||
[[ ${resp_get_payload} == ${expected_resp_get_payload} ]] || [[ ${resp_get_payload} == ${empirical_resp_get_payload} ]] || (echo "Unexpected response to engine_getPayload"; false)
|
[[ ${resp_get_payload} == ${expected_resp_get_payload} ]] || [[ ${resp_get_payload} == ${empirical_resp_get_payload} ]] || (echo "Unexpected response to engine_getPayloadV1"; false)
|
||||||
|
|
||||||
# Execute the payload
|
# Execute the payload
|
||||||
# Needed two tweaks vs upstream note: (a) add blockNumber field and (b) switch receiptRoots to receiptRoot
|
# Needed two tweaks vs upstream note: (a) add blockNumber field and (b) switch receiptRoots to receiptRoot
|
||||||
resp_execute_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_executePayload","params":[{"blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858","parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x7","transactions":[]}],"id":67}' http://localhost:8550)
|
resp_execute_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_executePayloadV1","params":[{"blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858","parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x7","transactions":[]}],"id":67}' http://localhost:8550)
|
||||||
[[ ${resp_execute_payload} == '{"jsonrpc":"2.0","id":67,"result":{"status":"VALID"}}' ]] || (echo "Unexpected response to engine_executePayload"; false)
|
[[ ${resp_execute_payload} == '{"jsonrpc":"2.0","id":67,"result":{"status":"VALID"}}' ]] || (echo "Unexpected response to engine_executePayloadV1"; false)
|
||||||
|
|
||||||
# Update the fork choice
|
# Update the fork choice
|
||||||
resp_fork_choice_updated=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_forkchoiceUpdated","params":[{"headBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", "finalizedBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"}],"id":67}' http://localhost:8550)
|
resp_fork_choice_updated=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_forkchoiceUpdatedV1","params":[{"headBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", "finalizedBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"}],"id":67}' http://localhost:8550)
|
||||||
[[ ${resp_consensus_validated} == '{"jsonrpc":"2.0","id":67,"result":null}' ]] || (echo "Unexpected response to engine_forkChoiceUpdated"; false)
|
[[ ${resp_consensus_validated} == '{"jsonrpc":"2.0","id":67,"result":null}' ]] || (echo "Unexpected response to engine_forkchoiceUpdatedV1"; false)
|
||||||
|
|
||||||
echo "Execution test vectors for Merge passed"
|
echo "Execution test vectors for Merge passed"
|
||||||
|
|
|
@ -20,6 +20,7 @@ $SCRIPT_DIR/../../build/nimbus \
|
||||||
--custom-network:"$SCRIPT_DIR/amphora-interop-genesis-m1.json" \
|
--custom-network:"$SCRIPT_DIR/amphora-interop-genesis-m1.json" \
|
||||||
--network:0 \
|
--network:0 \
|
||||||
--engine-api \
|
--engine-api \
|
||||||
|
--engine-api-port:8545 \
|
||||||
--rpc \
|
--rpc \
|
||||||
--nat:none --discovery:none \
|
--nat:none --discovery:none \
|
||||||
--import-key:"$SCRIPT_DIR/signer-key.txt" \
|
--import-key:"$SCRIPT_DIR/signer-key.txt" \
|
||||||
|
|
|
@ -9,7 +9,7 @@ import
|
||||||
asynctest, json, strformat, strutils, options, tables, os,
|
asynctest, json, strformat, strutils, options, tables, os,
|
||||||
nimcrypto, stew/byteutils, times,
|
nimcrypto, stew/byteutils, times,
|
||||||
json_rpc/[rpcserver, rpcclient], eth/common as eth_common,
|
json_rpc/[rpcserver, rpcclient], eth/common as eth_common,
|
||||||
eth/[rlp, keys, trie/db, p2p/private/p2p_types],
|
eth/[rlp, keys, trie/db, p2p/private/p2p_types], web3/conversions,
|
||||||
../nimbus/rpc/[common, p2p, hexstrings, rpc_types, rpc_utils],
|
../nimbus/rpc/[common, p2p, hexstrings, rpc_types, rpc_utils],
|
||||||
../nimbus/[constants, config, genesis, utils, transaction,
|
../nimbus/[constants, config, genesis, utils, transaction,
|
||||||
vm_state, vm_types],
|
vm_state, vm_types],
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 16ae908e49dad3dd1be1d536798a2b0ae39250df
|
Subproject commit 7daafe7b9cdfc3743c4b924eca6621dc928cf138
|
Loading…
Reference in New Issue