kintsugi merge vector tests (#3072)

This commit is contained in:
tersec 2021-11-10 11:41:02 +00:00 committed by GitHub
parent ec650c7fd7
commit 97ad5d49b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 60 deletions

View File

@ -420,14 +420,25 @@ proc executePayload*(p: Web3DataProviderRef,
p.web3.provider.engine_executePayloadV1(payload)
proc forkchoiceUpdated*(p: Web3DataProviderRef,
headBlock, finalizedBlock: Eth2Digest):
headBlock, finalizedBlock: Eth2Digest,
timestamp: uint64,
randomData: array[32, byte],
feeRecipient: Eth1Address):
Future[engine_api.ForkchoiceUpdatedResponse] =
p.web3.provider.engine_forkchoiceUpdatedV1(
ForkchoiceStateV1(
headBlockHash: headBlock.asBlockHash,
safeBlockHash: finalizedBlock.asBlockHash,
# https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
# "CL client software MUST use headBlockHash value as a stub for the
# safeBlockHash parameter"
safeBlockHash: headBlock.asBlockHash,
finalizedBlockHash: finalizedBlock.asBlockHash),
none(engine_api.PayloadAttributesV1))
some(engine_api.PayloadAttributesV1(
timestamp: Quantity timestamp,
random: FixedBytes[32] randomData,
feeRecipient: feeRecipient)))
template readJsonField(j: JsonNode, fieldName: string, ValueType: type): untyped =
var res: ValueType

View File

@ -40,9 +40,6 @@ type
BloomLogs* = object
data*: array[BYTES_PER_LOGS_BLOOM, byte]
# https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.4/src/engine/interop/specification.md#returns
PayloadId* = uint64
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/merge/beacon-chain.md#executionpayload
ExecutionPayload* = object
parent_hash*: Eth2Digest

View File

@ -3,40 +3,45 @@ set -Eeuo pipefail
# https://notes.ethereum.org/@9AeMAlpyQYaAAyuj47BzRw/rkwW3ceVY
#
# git clone --branch merge-interop-spec https://github.com/MariusVanDerWijden/go-ethereum.git
# git clone --branch kintsugi-spec https://github.com/MariusVanDerWijden/go-ethereum.git
#
# Last checked against geth as of
# commit d6b04900423634d27be1178edf46622394085bb9 (HEAD -> merge-interop-spec, origin/merge-interop-spec)
# commit 98240256ee51811c6b2806783c160aaf6f965f6b (HEAD -> kintsugi-spec, origin/kintsugi-spec)
# Author: Marius van der Wijden <m.vanderwijden@live.de>
# Date: Wed Sep 29 19:24:56 2021 +0200
# Date: Sat Nov 6 14:28:21 2021 +0100
#
# eth/catalyst: fix random in payload, payloadid as hexutil
# eth/catalyst: remove headHash from payloadAttributes
# Prepare a payload
resp_prepare_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_preparePayload","params":[{"parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131", "timestamp":"0x5", "random":"0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient":"0x0000000000000000000000000000000000000000"}],"id":67}' http://localhost:8545)
echo "engine_preparePayload response: ${resp_prepare_payload}"
# Interop version of response, not current main version of response
[[ ${resp_prepare_payload} == '{"jsonrpc":"2.0","id":67,"result":"0x0"}' ]] || (echo "Unexpected response to engine_preparePayload"; false)
# Prepare payload
resp_prepare_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_forkchoiceUpdatedV1","params":[{"headBlockHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a", "safeBlockHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a", "finalizedBlockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}, {"timestamp":"0x5", "random":"0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"}],"id":67}' http://localhost:8545)
echo "engine_forkchoiceUpdatedV1 response: ${resp_prepare_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:8545)
echo "engine_getPayload response: ${resp_get_payload}"
# Inconsistency in test vectors vs Geth behavior
expected_resp_prepare_payload='{"jsonrpc":"2.0","id":67,"result":{"status":"VALID","payloadId":"0xa247243752eb10b4"}}'
empirical_resp_prepare_payload='{"jsonrpc":"2.0","id":67,"result":{"status":"SUCCESS","payloadId":"0xa247243752eb10b4"}}'
[[ ${resp_prepare_payload} == "${expected_resp_prepare_payload}" ]] || [[ ${resp_prepare_payload} == "${empirical_resp_prepare_payload}" ]] || (echo "Unexpected response to engine_forkchoiceUpdatedV1"; false)
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":[]}}'
[[ ${resp_get_payload} == ${expected_resp_get_payload} ]] || [[ ${resp_get_payload} == ${empirical_resp_get_payload} ]] || (echo "Unexpected response to engine_getPayload"; false)
# Get payload
resp_get_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_getPayloadV1","params":["0xa247243752eb10b4"],"id":67}' http://localhost:8545)
echo "engine_getPayloadV1 response: ${resp_get_payload}"
# Execute the payload
# 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":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174","parentHash":"0xa0513a503d5bd6e89a144c3268e5b7e9da9dbf63df125a360e3950a7d0d67131","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x1","gasLimit":"0x989680","gasUsed":"0x0","blockNumber":"0x1","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x0","transactions":[]}],"id":67}' http://localhost:8545)
[[ ${resp_execute_payload} == '{"jsonrpc":"2.0","id":67,"result":{"status":"VALID"}}' ]] || (echo "Unexpected response to engine_executePayload"; false)
expected_resp_get_payload='{"jsonrpc":"2.0","id":67,"result":{"parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x7","blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858","transactions":[]}}'
[[ ${resp_get_payload} == "${expected_resp_get_payload}" ]] || (echo "Unexpected response to engine_getPayloadV1"; false)
# Mark the payload as valid
resp_consensus_validated=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_consensusValidated","params":[{"blockHash":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", "status":"VALID"}],"id":67}' http://localhost:8545)
[[ ${resp_consensus_validated} == '{"jsonrpc":"2.0","id":67,"result":null}' ]] || (echo "Unexpected response to engine_consensusValidated"; false)
# Execute payload
resp_execute_payload=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_executePayloadV1","params":[{"parentHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a","coinbase":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","stateRoot":"0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45","receiptRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","random":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","gasLimit":"0x1c9c380","gasUsed":"0x0","timestamp":"0x5","extraData":"0x","baseFeePerGas":"0x7","blockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858","transactions":[]}],"id":67}' http://localhost:8545)
echo "engine_executePayloadV1 response: ${resp_execute_payload}"
# SUCCESS vs VALID again, but in the other direction
expected_resp_execute_payload='{"jsonrpc":"2.0","id":67,"result":{"status":"SUCCESS","latestValidHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"}}'
empirical_resp_execute_payload='{"jsonrpc":"2.0","id":67,"result":{"status":"VALID","latestValidHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858"}}'
[[ ${resp_execute_payload} == "${expected_resp_execute_payload}" ]] || [[ ${resp_execute_payload} == "${empirical_resp_execute_payload}" ]] || (echo "Unexpected response to engine_executePayloadV1"; false)
# 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":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174", "finalizedBlockHash":"0xb084c10440f05f5a23a55d1d7ebcb1b3892935fb56f23cdc9a7f42c348eed174"}],"id":67}' http://localhost:8545)
[[ ${resp_consensus_validated} == '{"jsonrpc":"2.0","id":67,"result":null}' ]] || (echo "Unexpected response to engine_forkChoiceUpdated"; false)
resp_update_forkchoice=$(curl -sX POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"engine_forkchoiceUpdatedV1","params":[{"headBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", "safeBlockHash":"0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858", "finalizedBlockHash":"0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a"}, null],"id":67}' http://localhost:8545)
echo "engine_forkchoiceUpdatedV1 response: ${resp_update_forkchoice}"
echo "Execution test vectors for Merge passed"
expected_resp_update_forkchoice='{"jsonrpc":"2.0","id":67,"result":{"status":"SUCCESS","payloadId":"0x"}}'
[[ ${resp_update_forkchoice} == "${expected_resp_update_forkchoice}" ]] || (echo "Unexpected response to engine_forkchoiceUpdatedV1"; false)
echo "kintsugi test vectors passed"

View File

@ -1,21 +1,20 @@
#!/usr/bin/env bash
# set -Eeuo pipefail
# https://notes.ethereum.org/_UH57VUPRrC-re3ubtmo2w
# https://notes.ethereum.org/@9AeMAlpyQYaAAyuj47BzRw/rkwW3ceVY#Genesis
# Genesis block hash: 0x3b8fb240d288781d4aac94d3fd16809ee413bc99294a085798a589dae51ddd4a
# To start miner, run miner.start()
# To increase verbosity: debug.verbosity(4)
# MetaMask seed phrase for address with balance is:
# lecture manual soon title cloth uncle gesture cereal common fruit tooth crater
GENESISJSON=$(mktemp)
GETHDATADIR=$(mktemp -d)
echo \{\
\"config\": \{\
\"config\": \{\
\"chainId\":1,\
\"homesteadBlock\":0,\
\"eip150Block\":0,\
\"eip150Hash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\
\"eip155Block\":0,\
\"eip158Block\":0,\
\"byzantiumBlock\":0,\
@ -29,13 +28,13 @@ echo \{\
\"period\": 5,\
\"epoch\": 30000\
\},\
\"terminalTotalDifficulty\":10\
\"terminalTotalDifficulty\":0\
\},\
\"nonce\":\"0x42\",\
\"timestamp\":\"0x0\",\
\"extraData\":\"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\
\"gasLimit\":\"0x1C9C380\",\
\"difficulty\":\"0x0\",\
\"difficulty\":\"0x400000000\",\
\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\
\"coinbase\":\"0x0000000000000000000000000000000000000000\",\
\"alloc\":\{\
@ -54,4 +53,4 @@ echo \{\
~/execution_clients/go-ethereum/build/bin/geth --catalyst --http --ws -http.api "engine" --datadir "${GETHDATADIR}" account import <(echo 45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8)
# Start the node (and press enter once to unlock the account)
~/execution_clients/go-ethereum/build/bin/geth --catalyst --http --ws -ws.api "eth,net,engine" --datadir "${GETHDATADIR}" --allow-insecure-unlock --unlock "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" --password "" --nodiscover console
~/execution_clients/go-ethereum/build/bin/geth --catalyst --http --ws --http.api "eth,net,engine" -ws.api "eth,net,engine" --datadir "${GETHDATADIR}" --allow-insecure-unlock --unlock "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" --password "" --nodiscover console

View File

@ -14,37 +14,39 @@ suite "Merge test vectors":
let web3Provider = (waitFor Web3DataProvider.new(
default(Eth1Address), "ws://127.0.0.1:8546")).get
test "preparePayload, getPayload, executePayload, and forkchoiceUpdated":
test "getPayload, executePayload, and forkchoiceUpdated":
const feeRecipient =
Eth1Address.fromHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")
let
existingBlock = waitFor web3Provider.getBlockByNumber(5)
payloadId = waitFor web3Provider.preparePayload(
existingBlock = waitFor web3Provider.getBlockByNumber(1)
payloadId = waitFor web3Provider.forkchoiceUpdated(
existingBlock.hash.asEth2Digest,
existingBlock.hash.asEth2Digest,
existingBlock.timestamp.uint64 + 12,
default(Eth2Digest).data, # Random
Eth1Address.fromHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) # Fee recipient
feeRecipient)
payload = waitFor web3Provider.getPayload(
Quantity(payloadId.payloadId))
Quantity(payloadId.payloadId.get))
payloadStatus = waitFor web3Provider.executePayload(payload)
fcupdatedStatus = waitFor web3Provider.forkchoiceUpdated(
payload.blockHash.asEth2Digest, payload.blockHash.asEth2Digest)
payloadId2 = waitFor web3Provider.preparePayload(
payload.blockHash.asEth2Digest,
payload.blockHash.asEth2Digest,
existingBlock.timestamp.uint64 + 24,
default(Eth2Digest).data, # Random
Eth1Address.fromHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")) # Fee recipient
feeRecipient)
payload2 = waitFor web3Provider.getPayload(
Quantity(payloadId2.payloadId))
Quantity(fcupdatedStatus.payloadId.get))
payloadStatus2 = waitFor web3Provider.executePayload(payload2)
fcupdatedStatus2 = waitFor web3Provider.forkchoiceUpdated(
payload2.blockHash.asEth2Digest, payload2.blockHash.asEth2Digest)
payload2.blockHash.asEth2Digest,
payload2.blockHash.asEth2Digest,
existingBlock.timestamp.uint64 + 36,
default(Eth2Digest).data, # Random
feeRecipient)
check: payloadStatus.status == "VALID"
test "getPayload unknown payload":
try:
let res = waitFor web3Provider.getPayload(Quantity(100000))
doAssert false
except ValueError as e:
# expected outcome
echo e.msg
check:
payloadStatus.status == "VALID"
fcupdatedStatus.status == "SUCCESS"
payloadStatus2.status == "VALID"
fcupdatedStatus2.status == "SUCCESS"

2
vendor/nim-web3 vendored

@ -1 +1 @@
Subproject commit 94635bbe2017d0bbdd69c872a6a14cbc46c276c0
Subproject commit 183cc8f407082a44fec18492a8c18a8261cdd27f