Add BeaconSync reorg tests (#1782)
* Add BeaconSync reorg tests * Fix redefinition error in tx_sender.nim
This commit is contained in:
parent
2f2c5127ea
commit
501d8a369a
|
@ -75,11 +75,6 @@ type
|
||||||
onSafeBlockChange * : proc(): bool {.gcsafe.}
|
onSafeBlockChange * : proc(): bool {.gcsafe.}
|
||||||
onFinalizedBlockChange* : proc(): bool {.gcsafe.}
|
onFinalizedBlockChange* : proc(): bool {.gcsafe.}
|
||||||
|
|
||||||
GetPayloadResponse = object
|
|
||||||
executionPayload: ExecutionPayload
|
|
||||||
blockValue: Option[UInt256]
|
|
||||||
blobsBundle: Option[BlobsBundleV1]
|
|
||||||
|
|
||||||
func latestPayloadNumber*(h: Table[uint64, ExecutionPayload]): uint64 =
|
func latestPayloadNumber*(h: Table[uint64, ExecutionPayload]): uint64 =
|
||||||
result = 0'u64
|
result = 0'u64
|
||||||
for n, _ in h:
|
for n, _ in h:
|
||||||
|
@ -99,17 +94,21 @@ func latestWithdrawalsIndex*(h: Table[uint64, ExecutionPayload]): uint64 =
|
||||||
func client(cl: CLMocker): RpcClient =
|
func client(cl: CLMocker): RpcClient =
|
||||||
cl.clients.first.client
|
cl.clients.first.client
|
||||||
|
|
||||||
proc init(cl: CLMocker, clients: ClientPool, com: CommonRef) =
|
proc init(cl: CLMocker, eng: EngineEnv, com: CommonRef) =
|
||||||
cl.clients = clients
|
cl.clients = ClientPool()
|
||||||
|
cl.clients.add eng
|
||||||
cl.com = com
|
cl.com = com
|
||||||
cl.slotsToSafe = 1
|
cl.slotsToSafe = 1
|
||||||
cl.slotsToFinalized = 2
|
cl.slotsToFinalized = 2
|
||||||
cl.payloadProductionClientDelay = 1
|
cl.payloadProductionClientDelay = 1
|
||||||
cl.headerHistory[0] = com.genesisHeader()
|
cl.headerHistory[0] = com.genesisHeader()
|
||||||
|
|
||||||
proc newClMocker*(clients: ClientPool, com: CommonRef): CLMocker =
|
proc newClMocker*(eng: EngineEnv, com: CommonRef): CLMocker =
|
||||||
new result
|
new result
|
||||||
result.init(clients, com)
|
result.init(eng, com)
|
||||||
|
|
||||||
|
proc addEngine*(cl: CLMocker, eng: EngineEnv) =
|
||||||
|
cl.clients.add eng
|
||||||
|
|
||||||
proc waitForTTD*(cl: CLMocker): Future[bool] {.async.} =
|
proc waitForTTD*(cl: CLMocker): Future[bool] {.async.} =
|
||||||
let ttd = cl.com.ttd()
|
let ttd = cl.com.ttd()
|
||||||
|
@ -193,32 +192,6 @@ func isCancun(cl: CLMocker, timestamp: Quantity): bool =
|
||||||
let ts = fromUnix(timestamp.int64)
|
let ts = fromUnix(timestamp.int64)
|
||||||
cl.com.isCancunOrLater(ts)
|
cl.com.isCancunOrLater(ts)
|
||||||
|
|
||||||
func V1(attr: Option[PayloadAttributes]): Option[PayloadAttributesV1] =
|
|
||||||
if attr.isNone:
|
|
||||||
return none(PayloadAttributesV1)
|
|
||||||
some(attr.get.V1)
|
|
||||||
|
|
||||||
when false:
|
|
||||||
func V2(attr: Option[PayloadAttributes]): Option[PayloadAttributesV2] =
|
|
||||||
if attr.isNone:
|
|
||||||
return none(PayloadAttributesV2)
|
|
||||||
some(attr.get.V2)
|
|
||||||
|
|
||||||
func V3(attr: Option[PayloadAttributes]): Option[PayloadAttributesV3] =
|
|
||||||
if attr.isNone:
|
|
||||||
return none(PayloadAttributesV3)
|
|
||||||
some(attr.get.V3)
|
|
||||||
|
|
||||||
proc fcu(cl: CLMocker, version: Version,
|
|
||||||
update: ForkchoiceStateV1,
|
|
||||||
attr: Option[PayloadAttributes]):
|
|
||||||
Result[ForkchoiceUpdatedResponse, string] =
|
|
||||||
let client = cl.nextBlockProducer.client
|
|
||||||
case version
|
|
||||||
of Version.V1: client.forkchoiceUpdatedV1(update, attr.V1)
|
|
||||||
of Version.V2: client.forkchoiceUpdatedV2(update, attr)
|
|
||||||
of Version.V3: client.forkchoiceUpdatedV3(update, attr)
|
|
||||||
|
|
||||||
# Picks the next payload producer from the set of clients registered
|
# Picks the next payload producer from the set of clients registered
|
||||||
proc pickNextPayloadProducer(cl: CLMocker): bool =
|
proc pickNextPayloadProducer(cl: CLMocker): bool =
|
||||||
doAssert cl.clients.len != 0
|
doAssert cl.clients.len != 0
|
||||||
|
@ -274,7 +247,8 @@ proc requestNextPayload(cl: CLMocker): bool =
|
||||||
cl.prevRandaoHistory[number] = nextPrevRandao
|
cl.prevRandaoHistory[number] = nextPrevRandao
|
||||||
|
|
||||||
let version = cl.latestPayloadAttributes.version
|
let version = cl.latestPayloadAttributes.version
|
||||||
let res = cl.fcu(version, cl.latestForkchoice, some(cl.latestPayloadAttributes))
|
let client = cl.nextBlockProducer.client
|
||||||
|
let res = client.forkchoiceUpdated(version, cl.latestForkchoice, some(cl.latestPayloadAttributes))
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
error "CLMocker: Could not send forkchoiceUpdated", version=version, msg=res.error
|
error "CLMocker: Could not send forkchoiceUpdated", version=version, msg=res.error
|
||||||
return false
|
return false
|
||||||
|
@ -299,32 +273,11 @@ proc getPayload(cl: CLMocker, payloadId: PayloadID): Result[GetPayloadResponse,
|
||||||
let ts = cl.latestPayloadAttributes.timestamp
|
let ts = cl.latestPayloadAttributes.timestamp
|
||||||
let client = cl.nextBlockProducer.client
|
let client = cl.nextBlockProducer.client
|
||||||
if cl.isCancun(ts):
|
if cl.isCancun(ts):
|
||||||
let res = client.getPayloadV3(payloadId)
|
client.getPayload(payloadId, Version.V3)
|
||||||
if res.isErr:
|
elif cl.isShanghai(ts):
|
||||||
return err(res.error)
|
client.getPayload(payloadId, Version.V2)
|
||||||
let x = res.get
|
else:
|
||||||
return ok(GetPayloadResponse(
|
client.getPayload(payloadId, Version.V1)
|
||||||
executionPayload: executionPayload(x.executionPayload),
|
|
||||||
blockValue: some(x.blockValue),
|
|
||||||
blobsBundle: some(x.blobsBundle)
|
|
||||||
))
|
|
||||||
|
|
||||||
if cl.isShanghai(ts):
|
|
||||||
let res = client.getPayloadV2(payloadId)
|
|
||||||
if res.isErr:
|
|
||||||
return err(res.error)
|
|
||||||
let x = res.get
|
|
||||||
return ok(GetPayloadResponse(
|
|
||||||
executionPayload: executionPayload(x.executionPayload),
|
|
||||||
blockValue: some(x.blockValue)
|
|
||||||
))
|
|
||||||
|
|
||||||
let res = client.getPayloadV1(payloadId)
|
|
||||||
if res.isErr:
|
|
||||||
return err(res.error)
|
|
||||||
return ok(GetPayloadResponse(
|
|
||||||
executionPayload: executionPayload(res.get),
|
|
||||||
))
|
|
||||||
|
|
||||||
proc getNextPayload(cl: CLMocker): bool =
|
proc getNextPayload(cl: CLMocker): bool =
|
||||||
let res = cl.getPayload(cl.nextPayloadID)
|
let res = cl.getPayload(cl.nextPayloadID)
|
||||||
|
@ -451,7 +404,8 @@ proc broadcastNextNewPayload(cl: CLMocker): bool =
|
||||||
proc broadcastForkchoiceUpdated(cl: CLMocker,
|
proc broadcastForkchoiceUpdated(cl: CLMocker,
|
||||||
update: ForkchoiceStateV1): Result[ForkchoiceUpdatedResponse, string] =
|
update: ForkchoiceStateV1): Result[ForkchoiceUpdatedResponse, string] =
|
||||||
let version = cl.latestExecutedPayload.version
|
let version = cl.latestExecutedPayload.version
|
||||||
cl.fcu(version, update, none(PayloadAttributes))
|
let client = cl.nextBlockProducer.client
|
||||||
|
client.forkchoiceUpdated(version, update, none(PayloadAttributes))
|
||||||
|
|
||||||
proc broadcastLatestForkchoice(cl: CLMocker): bool =
|
proc broadcastLatestForkchoice(cl: CLMocker): bool =
|
||||||
let res = cl.broadcastForkchoiceUpdated(cl.latestForkchoice)
|
let res = cl.broadcastForkchoiceUpdated(cl.latestForkchoice)
|
||||||
|
@ -480,7 +434,6 @@ proc broadcastLatestForkchoice(cl: CLMocker): bool =
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe.} =
|
proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe.} =
|
||||||
doAssert(cl.ttdReached)
|
doAssert(cl.ttdReached)
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,6 @@ type
|
||||||
slotsToFinalized*: int
|
slotsToFinalized*: int
|
||||||
slotsToSafe*: int
|
slotsToSafe*: int
|
||||||
|
|
||||||
const
|
|
||||||
prevRandaoContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
|
||||||
|
|
||||||
template testNP(res, cond: untyped, validHash = none(common.Hash256)) =
|
template testNP(res, cond: untyped, validHash = none(common.Hash256)) =
|
||||||
testCond res.isOk
|
testCond res.isOk
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
|
|
|
@ -11,7 +11,9 @@ import
|
||||||
|
|
||||||
import web3/engine_api as web3_engine_api
|
import web3/engine_api as web3_engine_api
|
||||||
|
|
||||||
export execution_types
|
export
|
||||||
|
execution_types,
|
||||||
|
rpcclient
|
||||||
|
|
||||||
type
|
type
|
||||||
Hash256 = eth_types.Hash256
|
Hash256 = eth_types.Hash256
|
||||||
|
@ -43,20 +45,6 @@ proc forkchoiceUpdatedV1*(client: RpcClient,
|
||||||
wrapTrySimpleRes:
|
wrapTrySimpleRes:
|
||||||
client.engine_forkchoiceUpdatedV1(update, payloadAttributes)
|
client.engine_forkchoiceUpdatedV1(update, payloadAttributes)
|
||||||
|
|
||||||
#proc forkchoiceUpdatedV2*(client: RpcClient,
|
|
||||||
# update: ForkchoiceStateV1,
|
|
||||||
# payloadAttributes = none(PayloadAttributesV2)):
|
|
||||||
# Result[ForkchoiceUpdatedResponse, string] =
|
|
||||||
# wrapTrySimpleRes:
|
|
||||||
# client.engine_forkchoiceUpdatedV2(update, payloadAttributes)
|
|
||||||
|
|
||||||
#proc forkchoiceUpdatedV3*(client: RpcClient,
|
|
||||||
# update: ForkchoiceStateV1,
|
|
||||||
# payloadAttributes = none(PayloadAttributesV3)):
|
|
||||||
# Result[ForkchoiceUpdatedResponse, string] =
|
|
||||||
# wrapTrySimpleRes:
|
|
||||||
# client.engine_forkchoiceUpdatedV3(update, payloadAttributes)
|
|
||||||
|
|
||||||
proc forkchoiceUpdatedV2*(client: RpcClient,
|
proc forkchoiceUpdatedV2*(client: RpcClient,
|
||||||
update: ForkchoiceStateV1,
|
update: ForkchoiceStateV1,
|
||||||
payloadAttributes = none(PayloadAttributes)):
|
payloadAttributes = none(PayloadAttributes)):
|
||||||
|
@ -83,6 +71,50 @@ proc getPayloadV3*(client: RpcClient, payloadId: PayloadID): Result[GetPayloadV3
|
||||||
wrapTrySimpleRes:
|
wrapTrySimpleRes:
|
||||||
client.engine_getPayloadV3(payloadId)
|
client.engine_getPayloadV3(payloadId)
|
||||||
|
|
||||||
|
proc getPayload*(client: RpcClient,
|
||||||
|
payloadId: PayloadID,
|
||||||
|
version: Version): Result[GetPayloadResponse, string] =
|
||||||
|
if version == Version.V3:
|
||||||
|
let x = client.getPayloadV3(payloadId).valueOr:
|
||||||
|
return err(error)
|
||||||
|
ok(GetPayloadResponse(
|
||||||
|
executionPayload: executionPayload(x.executionPayload),
|
||||||
|
blockValue: some(x.blockValue),
|
||||||
|
blobsBundle: some(x.blobsBundle)
|
||||||
|
))
|
||||||
|
elif version == Version.V2:
|
||||||
|
let x = client.getPayloadV2(payloadId).valueOr:
|
||||||
|
return err(error)
|
||||||
|
ok(GetPayloadResponse(
|
||||||
|
executionPayload: executionPayload(x.executionPayload),
|
||||||
|
blockValue: some(x.blockValue)
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
let x = client.getPayloadV1(payloadId).valueOr:
|
||||||
|
return err(error)
|
||||||
|
ok(GetPayloadResponse(
|
||||||
|
executionPayload: executionPayload(x),
|
||||||
|
))
|
||||||
|
|
||||||
|
proc forkchoiceUpdated*(client: RpcClient,
|
||||||
|
update: ForkchoiceStateV1,
|
||||||
|
attr: PayloadAttributes):
|
||||||
|
Result[ForkchoiceUpdatedResponse, string] =
|
||||||
|
case attr.version
|
||||||
|
of Version.V1: client.forkchoiceUpdatedV1(update, some attr.V1)
|
||||||
|
of Version.V2: client.forkchoiceUpdatedV2(update, some attr)
|
||||||
|
of Version.V3: client.forkchoiceUpdatedV3(update, some attr)
|
||||||
|
|
||||||
|
proc forkchoiceUpdated*(client: RpcClient,
|
||||||
|
version: Version,
|
||||||
|
update: ForkchoiceStateV1,
|
||||||
|
attr = none(PayloadAttributes)):
|
||||||
|
Result[ForkchoiceUpdatedResponse, string] =
|
||||||
|
case version
|
||||||
|
of Version.V1: client.forkchoiceUpdatedV1(update, attr.V1)
|
||||||
|
of Version.V2: client.forkchoiceUpdatedV2(update, attr)
|
||||||
|
of Version.V3: client.forkchoiceUpdatedV3(update, attr)
|
||||||
|
|
||||||
proc newPayloadV1*(client: RpcClient,
|
proc newPayloadV1*(client: RpcClient,
|
||||||
payload: ExecutionPayloadV1):
|
payload: ExecutionPayloadV1):
|
||||||
Result[PayloadStatusV1, string] =
|
Result[PayloadStatusV1, string] =
|
||||||
|
@ -110,6 +142,15 @@ proc newPayloadV3*(client: RpcClient,
|
||||||
wrapTrySimpleRes:
|
wrapTrySimpleRes:
|
||||||
client.engine_newPayloadV3(payload, versionedHashes, parentBeaconBlockRoot)
|
client.engine_newPayloadV3(payload, versionedHashes, parentBeaconBlockRoot)
|
||||||
|
|
||||||
|
proc newPayload*(client: RpcClient,
|
||||||
|
payload: ExecutionPayload,
|
||||||
|
version: Version):
|
||||||
|
Result[PayloadStatusV1, string] =
|
||||||
|
if version == Version.V1:
|
||||||
|
client.newPayloadV1(payload.V1)
|
||||||
|
else:
|
||||||
|
client.newPayloadV2(payload.V2)
|
||||||
|
|
||||||
proc exchangeCapabilities*(client: RpcClient,
|
proc exchangeCapabilities*(client: RpcClient,
|
||||||
methods: seq[string]):
|
methods: seq[string]):
|
||||||
Result[seq[string], string] =
|
Result[seq[string], string] =
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import
|
import
|
||||||
std/[os, math],
|
std/os,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
eth/p2p as eth_p2p,
|
eth/p2p as eth_p2p,
|
||||||
chronos,
|
chronos,
|
||||||
json_rpc/[rpcserver, rpcclient],
|
json_rpc/[rpcserver, rpcclient],
|
||||||
stew/[results, byteutils],
|
stew/[results],
|
||||||
../../../nimbus/[
|
../../../nimbus/[
|
||||||
config,
|
config,
|
||||||
constants,
|
constants,
|
||||||
transaction,
|
|
||||||
core/sealer,
|
core/sealer,
|
||||||
core/chain,
|
core/chain,
|
||||||
core/tx_pool,
|
core/tx_pool,
|
||||||
|
@ -20,25 +19,12 @@ import
|
||||||
beacon/beacon_engine,
|
beacon/beacon_engine,
|
||||||
common
|
common
|
||||||
],
|
],
|
||||||
../../../tests/test_helpers,
|
../../../tests/test_helpers
|
||||||
./engine_client
|
|
||||||
|
|
||||||
export
|
export
|
||||||
results
|
results
|
||||||
|
|
||||||
type
|
type
|
||||||
BaseTx* = object of RootObj
|
|
||||||
recipient*: Option[EthAddress]
|
|
||||||
gasLimit* : GasInt
|
|
||||||
amount* : UInt256
|
|
||||||
payload* : seq[byte]
|
|
||||||
txType* : Option[TxType]
|
|
||||||
|
|
||||||
BigInitcodeTx* = object of BaseTx
|
|
||||||
initcodeLength*: int
|
|
||||||
padByte* : uint8
|
|
||||||
initcode* : seq[byte]
|
|
||||||
|
|
||||||
EngineEnv* = ref object
|
EngineEnv* = ref object
|
||||||
conf : NimbusConf
|
conf : NimbusConf
|
||||||
com : CommonRef
|
com : CommonRef
|
||||||
|
@ -46,8 +32,6 @@ type
|
||||||
server : RpcHttpServer
|
server : RpcHttpServer
|
||||||
sealer : SealingEngineRef
|
sealer : SealingEngineRef
|
||||||
ttd : DifficultyInt
|
ttd : DifficultyInt
|
||||||
tx : Transaction
|
|
||||||
nonce : uint64
|
|
||||||
client : RpcHttpClient
|
client : RpcHttpClient
|
||||||
sync : BeaconSyncRef
|
sync : BeaconSyncRef
|
||||||
|
|
||||||
|
@ -56,12 +40,8 @@ const
|
||||||
genesisFile = baseFolder & "/init/genesis.json"
|
genesisFile = baseFolder & "/init/genesis.json"
|
||||||
sealerKey = baseFolder & "/init/sealer.key"
|
sealerKey = baseFolder & "/init/sealer.key"
|
||||||
chainFolder = baseFolder & "/chains"
|
chainFolder = baseFolder & "/chains"
|
||||||
|
|
||||||
# This is the account that sends vault funding transactions.
|
|
||||||
vaultAddr* = hexToByteArray[20]("0xcf49fda3be353c69b41ed96333cd24302da4556f")
|
|
||||||
jwtSecret = "0x7365637265747365637265747365637265747365637265747365637265747365"
|
jwtSecret = "0x7365637265747365637265747365637265747365637265747365637265747365"
|
||||||
|
|
||||||
|
|
||||||
proc makeCom*(conf: NimbusConf): CommonRef =
|
proc makeCom*(conf: NimbusConf): CommonRef =
|
||||||
CommonRef.new(
|
CommonRef.new(
|
||||||
newCoreDbRef LegacyDbMemory,
|
newCoreDbRef LegacyDbMemory,
|
||||||
|
@ -189,98 +169,3 @@ func node*(env: EngineEnv): ENode =
|
||||||
|
|
||||||
proc connect*(env: EngineEnv, node: ENode) =
|
proc connect*(env: EngineEnv, node: ENode) =
|
||||||
waitFor env.node.connectToNode(node)
|
waitFor env.node.connectToNode(node)
|
||||||
|
|
||||||
func gwei(n: int64): GasInt {.compileTime.} =
|
|
||||||
GasInt(n * (10 ^ 9))
|
|
||||||
|
|
||||||
proc getTxType(tc: BaseTx, nonce: uint64): TxType =
|
|
||||||
if tc.txType.isNone:
|
|
||||||
if nonce mod 2 == 0:
|
|
||||||
TxLegacy
|
|
||||||
else:
|
|
||||||
TxEIP1559
|
|
||||||
else:
|
|
||||||
tc.txType.get
|
|
||||||
|
|
||||||
proc makeTx*(env: EngineEnv, vaultKey: PrivateKey, tc: BaseTx, nonce: AccountNonce): Transaction =
|
|
||||||
const
|
|
||||||
gasPrice = 30.gwei
|
|
||||||
gasTipPrice = 1.gwei
|
|
||||||
|
|
||||||
gasFeeCap = gasPrice
|
|
||||||
gasTipCap = gasTipPrice
|
|
||||||
|
|
||||||
let chainId = env.conf.networkParams.config.chainId
|
|
||||||
let txType = tc.getTxType(nonce)
|
|
||||||
|
|
||||||
# Build the transaction depending on the specified type
|
|
||||||
let tx = if txType == TxLegacy:
|
|
||||||
Transaction(
|
|
||||||
txType : TxLegacy,
|
|
||||||
nonce : nonce,
|
|
||||||
to : tc.recipient,
|
|
||||||
value : tc.amount,
|
|
||||||
gasLimit: tc.gasLimit,
|
|
||||||
gasPrice: gasPrice,
|
|
||||||
payload : tc.payload
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
Transaction(
|
|
||||||
txType : TxEIP1559,
|
|
||||||
nonce : nonce,
|
|
||||||
gasLimit: tc.gasLimit,
|
|
||||||
maxFee : gasFeeCap,
|
|
||||||
maxPriorityFee: gasTipCap,
|
|
||||||
to : tc.recipient,
|
|
||||||
value : tc.amount,
|
|
||||||
payload : tc.payload,
|
|
||||||
chainId : chainId
|
|
||||||
)
|
|
||||||
|
|
||||||
signTransaction(tx, vaultKey, chainId, eip155 = true)
|
|
||||||
|
|
||||||
proc makeTx*(env: EngineEnv, vaultKey: PrivateKey, tc: var BigInitcodeTx, nonce: AccountNonce): Transaction =
|
|
||||||
if tc.payload.len == 0:
|
|
||||||
# Prepare initcode payload
|
|
||||||
if tc.initcode.len != 0:
|
|
||||||
doAssert(tc.initcode.len <= tc.initcodeLength, "invalid initcode (too big)")
|
|
||||||
tc.payload = tc.initcode
|
|
||||||
|
|
||||||
while tc.payload.len < tc.initcodeLength:
|
|
||||||
tc.payload.add tc.padByte
|
|
||||||
|
|
||||||
doAssert(tc.recipient.isNone, "invalid configuration for big contract tx creator")
|
|
||||||
env.makeTx(vaultKey, tc.BaseTx, nonce)
|
|
||||||
|
|
||||||
proc sendNextTx*(env: EngineEnv, vaultKey: PrivateKey, tc: BaseTx): bool =
|
|
||||||
env.tx = env.makeTx(vaultKey, tc, env.nonce)
|
|
||||||
inc env.nonce
|
|
||||||
let rr = env.client.sendTransaction(env.tx)
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc sendTx*(env: EngineEnv, vaultKey: PrivateKey, tc: BaseTx, nonce: AccountNonce): bool =
|
|
||||||
env.tx = env.makeTx(vaultKey, tc, nonce)
|
|
||||||
let rr = env.client.sendTransaction(env.tx)
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc sendTx*(env: EngineEnv, vaultKey: PrivateKey, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
|
||||||
env.tx = env.makeTx(vaultKey, tc, nonce)
|
|
||||||
let rr = env.client.sendTransaction(env.tx)
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
||||||
proc sendTx*(env: EngineEnv, tx: Transaction): bool =
|
|
||||||
env.tx = tx
|
|
||||||
let rr = env.client.sendTransaction(env.tx)
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
return true
|
|
||||||
|
|
|
@ -7,13 +7,15 @@ import
|
||||||
./clmock,
|
./clmock,
|
||||||
./engine_client,
|
./engine_client,
|
||||||
./client_pool,
|
./client_pool,
|
||||||
./engine_env
|
./engine_env,
|
||||||
|
./tx_sender
|
||||||
|
|
||||||
export
|
export
|
||||||
clmock,
|
clmock,
|
||||||
engine_client,
|
engine_client,
|
||||||
client_pool,
|
client_pool,
|
||||||
engine_env
|
engine_env,
|
||||||
|
tx_sender
|
||||||
|
|
||||||
type
|
type
|
||||||
TestEnv* = ref object
|
TestEnv* = ref object
|
||||||
|
@ -23,26 +25,18 @@ type
|
||||||
port : int
|
port : int
|
||||||
rpcPort : int
|
rpcPort : int
|
||||||
clients : ClientPool
|
clients : ClientPool
|
||||||
|
sender : TxSender
|
||||||
clMock* : CLMocker
|
clMock* : CLMocker
|
||||||
vaultKey : PrivateKey
|
|
||||||
|
|
||||||
const
|
|
||||||
vaultKeyHex = "63b508a03c3b5937ceb903af8b1b0c191012ef6eb7e9c3fb7afa94e5d214d376"
|
|
||||||
|
|
||||||
proc makeEnv(conf: NimbusConf): TestEnv =
|
proc makeEnv(conf: NimbusConf): TestEnv =
|
||||||
let env = TestEnv(
|
TestEnv(
|
||||||
conf : conf,
|
conf : conf,
|
||||||
port : 30303,
|
port : 30303,
|
||||||
rpcPort: 8545,
|
rpcPort: 8545,
|
||||||
clients: ClientPool(),
|
clients: ClientPool(),
|
||||||
|
sender : TxSender.new(conf.networkParams),
|
||||||
)
|
)
|
||||||
|
|
||||||
env.vaultKey = PrivateKey.fromHex(vaultKeyHex).valueOr:
|
|
||||||
echo error
|
|
||||||
quit(QuitFailure)
|
|
||||||
|
|
||||||
env
|
|
||||||
|
|
||||||
proc addEngine(env: TestEnv, conf: var NimbusConf): EngineEnv =
|
proc addEngine(env: TestEnv, conf: var NimbusConf): EngineEnv =
|
||||||
conf.tcpPort = Port env.port
|
conf.tcpPort = Port env.port
|
||||||
conf.udpPort = Port env.port
|
conf.udpPort = Port env.port
|
||||||
|
@ -85,47 +79,58 @@ func engine*(env: TestEnv): EngineEnv =
|
||||||
env.clients.first
|
env.clients.first
|
||||||
|
|
||||||
proc setupCLMock*(env: TestEnv) =
|
proc setupCLMock*(env: TestEnv) =
|
||||||
env.clmock = newCLMocker(env.clients, env.engine.com)
|
env.clmock = newCLMocker(env.engine, env.engine.com)
|
||||||
|
|
||||||
proc addEngine*(env: TestEnv): EngineEnv =
|
proc addEngine*(env: TestEnv, addToCL: bool = true): EngineEnv =
|
||||||
|
doAssert(env.clMock.isNil.not)
|
||||||
var conf = env.conf # clone the conf
|
var conf = env.conf # clone the conf
|
||||||
let eng = env.addEngine(conf)
|
let eng = env.addEngine(conf)
|
||||||
eng.connect(env.engine.node)
|
eng.connect(env.engine.node)
|
||||||
|
if addToCL:
|
||||||
|
env.clMock.addEngine(eng)
|
||||||
eng
|
eng
|
||||||
|
|
||||||
proc makeTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx, nonce: AccountNonce): Transaction =
|
proc makeTx*(env: TestEnv, tc: BaseTx, nonce: AccountNonce): Transaction =
|
||||||
eng.makeTx(env.vaultKey, tc, nonce)
|
env.sender.makeTx(tc, nonce)
|
||||||
|
|
||||||
proc makeTx*(env: TestEnv, eng: EngineEnv, tc: var BigInitcodeTx, nonce: AccountNonce): Transaction =
|
proc makeTx*(env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): Transaction =
|
||||||
eng.makeTx(env.vaultKey, tc, nonce)
|
env.sender.makeTx(tc, nonce)
|
||||||
|
|
||||||
|
proc makeTxs*(env: TestEnv, tc: BaseTx, num: int): seq[Transaction] =
|
||||||
|
result = newSeqOfCap[Transaction](num)
|
||||||
|
for _ in 0..<num:
|
||||||
|
result.add env.sender.makeNextTx(tc)
|
||||||
|
|
||||||
proc sendNextTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx): bool =
|
proc sendNextTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx): bool =
|
||||||
eng.sendNextTx(env.vaultKey, tc)
|
env.sender.sendNextTx(eng.client, tc)
|
||||||
|
|
||||||
proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx, nonce: AccountNonce): bool =
|
proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx, nonce: AccountNonce): bool =
|
||||||
eng.sendTx(env.vaultKey, tc, nonce)
|
env.sender.sendTx(eng.client, tc, nonce)
|
||||||
|
|
||||||
proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
proc sendTx*(env: TestEnv, eng: EngineEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
||||||
eng.sendTx(env.vaultKey, tc, nonce)
|
env.sender.sendTx(eng.client, tc, nonce)
|
||||||
|
|
||||||
|
proc sendTxs*(env: TestEnv, eng: EngineEnv, txs: openArray[Transaction]): bool =
|
||||||
proc makeTx*(env: TestEnv, tc: BaseTx, nonce: AccountNonce): Transaction =
|
for tx in txs:
|
||||||
env.engine.makeTx(env.vaultKey, tc, nonce)
|
if not sendTx(eng.client, tx):
|
||||||
|
return false
|
||||||
proc makeTx*(env: TestEnv, tc: var BigInitcodeTx, nonce: AccountNonce): Transaction =
|
true
|
||||||
env.engine.makeTx(env.vaultKey, tc, nonce)
|
|
||||||
|
|
||||||
proc sendNextTx*(env: TestEnv, tc: BaseTx): bool =
|
proc sendNextTx*(env: TestEnv, tc: BaseTx): bool =
|
||||||
env.engine.sendNextTx(env.vaultKey, tc)
|
let client = env.engine.client
|
||||||
|
env.sender.sendNextTx(client, tc)
|
||||||
|
|
||||||
proc sendTx*(env: TestEnv, tc: BaseTx, nonce: AccountNonce): bool =
|
proc sendTx*(env: TestEnv, tc: BaseTx, nonce: AccountNonce): bool =
|
||||||
env.engine.sendTx(env.vaultKey, tc, nonce)
|
let client = env.engine.client
|
||||||
|
env.sender.sendTx(client, tc, nonce)
|
||||||
|
|
||||||
proc sendTx*(env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
proc sendTx*(env: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
||||||
env.engine.sendTx(env.vaultKey, tc, nonce)
|
let client = env.engine.client
|
||||||
|
env.sender.sendTx(client, tc, nonce)
|
||||||
|
|
||||||
proc sendTx*(env: TestEnv, tx: Transaction): bool =
|
proc sendTx*(env: TestEnv, tx: Transaction): bool =
|
||||||
env.engine.sendTx(tx)
|
let client = env.engine.client
|
||||||
|
sendTx(client, tx)
|
||||||
|
|
||||||
proc verifyPoWProgress*(env: TestEnv, lastBlockHash: common.Hash256): bool =
|
proc verifyPoWProgress*(env: TestEnv, lastBlockHash: common.Hash256): bool =
|
||||||
let res = waitFor env.client.verifyPoWProgress(lastBlockHash)
|
let res = waitFor env.client.verifyPoWProgress(lastBlockHash)
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
import
|
||||||
|
std/[tables, math],
|
||||||
|
eth/keys,
|
||||||
|
stew/endians2,
|
||||||
|
nimcrypto/sha2,
|
||||||
|
chronicles,
|
||||||
|
./engine_client,
|
||||||
|
../../../nimbus/transaction,
|
||||||
|
../../../nimbus/common
|
||||||
|
|
||||||
|
type
|
||||||
|
BaseTx* = object of RootObj
|
||||||
|
recipient*: Option[EthAddress]
|
||||||
|
gasLimit* : GasInt
|
||||||
|
amount* : UInt256
|
||||||
|
payload* : seq[byte]
|
||||||
|
txType* : Option[TxType]
|
||||||
|
|
||||||
|
BigInitcodeTx* = object of BaseTx
|
||||||
|
initcodeLength*: int
|
||||||
|
padByte* : uint8
|
||||||
|
initcode* : seq[byte]
|
||||||
|
|
||||||
|
TestAccount = object
|
||||||
|
key : PrivateKey
|
||||||
|
address: EthAddress
|
||||||
|
index : int
|
||||||
|
|
||||||
|
TxSender* = ref object
|
||||||
|
accounts: seq[TestAccount]
|
||||||
|
nonceMap: Table[EthAddress, uint64]
|
||||||
|
txSent : int
|
||||||
|
chainId : ChainID
|
||||||
|
|
||||||
|
MakeTxParams* = object
|
||||||
|
chainId*: ChainID
|
||||||
|
key* : PrivateKey
|
||||||
|
nonce* : AccountNonce
|
||||||
|
|
||||||
|
const
|
||||||
|
TestAccountCount = 1000
|
||||||
|
|
||||||
|
func toAddress(key: PrivateKey): EthAddress =
|
||||||
|
toKeyPair(key).pubkey.toCanonicalAddress()
|
||||||
|
|
||||||
|
proc createAccount(idx: int): TestAccount =
|
||||||
|
let
|
||||||
|
seed = toBytesBE(idx.uint64)
|
||||||
|
seedHash = sha256.digest(seed)
|
||||||
|
|
||||||
|
result.index = idx
|
||||||
|
result.key = PrivateKey.fromRaw(seedHash.data).valueOr:
|
||||||
|
echo error
|
||||||
|
quit(QuitFailure)
|
||||||
|
result.address = toAddress(result.key)
|
||||||
|
|
||||||
|
proc createAccounts(sender: TxSender) =
|
||||||
|
for i in 0..<TestAccountCount:
|
||||||
|
sender.accounts.add createAccount(i.int)
|
||||||
|
|
||||||
|
proc getNextAccount(sender: TxSender): TestAccount =
|
||||||
|
sender.accounts[sender.txSent mod sender.accounts.len]
|
||||||
|
|
||||||
|
proc getNextNonce(sender: TxSender, address: EthAddress): uint64 =
|
||||||
|
let nonce = sender.nonceMap.getOrDefault(address, 0'u64)
|
||||||
|
sender.nonceMap[address] = nonce + 1
|
||||||
|
nonce
|
||||||
|
|
||||||
|
proc fillBalance(sender: TxSender, params: NetworkParams) =
|
||||||
|
for x in sender.accounts:
|
||||||
|
params.genesis.alloc[x.address] = GenesisAccount(
|
||||||
|
balance: UInt256.fromHex("0x123450000000000000000"),
|
||||||
|
)
|
||||||
|
|
||||||
|
proc new*(_: type TxSender, params: NetworkParams): TxSender =
|
||||||
|
result = TxSender(chainId: params.config.chainId)
|
||||||
|
result.createAccounts()
|
||||||
|
result.fillBalance(params)
|
||||||
|
|
||||||
|
func gwei(n: int64): GasInt {.compileTime.} =
|
||||||
|
GasInt(n * (10 ^ 9))
|
||||||
|
|
||||||
|
proc getTxType(tc: BaseTx, nonce: uint64): TxType =
|
||||||
|
if tc.txType.isNone:
|
||||||
|
if nonce mod 2 == 0:
|
||||||
|
TxLegacy
|
||||||
|
else:
|
||||||
|
TxEIP1559
|
||||||
|
else:
|
||||||
|
tc.txType.get
|
||||||
|
|
||||||
|
proc makeTx(params: MakeTxParams, tc: BaseTx): Transaction =
|
||||||
|
const
|
||||||
|
gasPrice = 30.gwei
|
||||||
|
gasTipPrice = 1.gwei
|
||||||
|
|
||||||
|
gasFeeCap = gasPrice
|
||||||
|
gasTipCap = gasTipPrice
|
||||||
|
|
||||||
|
let txType = tc.getTxType(params.nonce)
|
||||||
|
|
||||||
|
# Build the transaction depending on the specified type
|
||||||
|
let tx = if txType == TxLegacy:
|
||||||
|
Transaction(
|
||||||
|
txType : TxLegacy,
|
||||||
|
nonce : params.nonce,
|
||||||
|
to : tc.recipient,
|
||||||
|
value : tc.amount,
|
||||||
|
gasLimit: tc.gasLimit,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
payload : tc.payload
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
Transaction(
|
||||||
|
txType : TxEIP1559,
|
||||||
|
nonce : params.nonce,
|
||||||
|
gasLimit: tc.gasLimit,
|
||||||
|
maxFee : gasFeeCap,
|
||||||
|
maxPriorityFee: gasTipCap,
|
||||||
|
to : tc.recipient,
|
||||||
|
value : tc.amount,
|
||||||
|
payload : tc.payload,
|
||||||
|
chainId : params.chainId
|
||||||
|
)
|
||||||
|
|
||||||
|
signTransaction(tx, params.key, params.chainId, eip155 = true)
|
||||||
|
|
||||||
|
proc makeTx(params: MakeTxParams, tc: BigInitcodeTx): Transaction =
|
||||||
|
var tx = tc
|
||||||
|
if tx.payload.len == 0:
|
||||||
|
# Prepare initcode payload
|
||||||
|
if tx.initcode.len != 0:
|
||||||
|
doAssert(tx.initcode.len <= tx.initcodeLength, "invalid initcode (too big)")
|
||||||
|
tx.payload = tx.initcode
|
||||||
|
|
||||||
|
while tx.payload.len < tx.initcodeLength:
|
||||||
|
tx.payload.add tx.padByte
|
||||||
|
|
||||||
|
doAssert(tx.recipient.isNone, "invalid configuration for big contract tx creator")
|
||||||
|
params.makeTx(tx.BaseTx)
|
||||||
|
|
||||||
|
proc makeTx*(sender: TxSender, tc: BaseTx, nonce: AccountNonce): Transaction =
|
||||||
|
let acc = sender.getNextAccount()
|
||||||
|
let params = MakeTxParams(
|
||||||
|
chainId: sender.chainId,
|
||||||
|
key: acc.key,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
params.makeTx(tc)
|
||||||
|
|
||||||
|
proc makeTx*(sender: TxSender, tc: BigInitcodeTx, nonce: AccountNonce): Transaction =
|
||||||
|
let acc = sender.getNextAccount()
|
||||||
|
let params = MakeTxParams(
|
||||||
|
chainId: sender.chainId,
|
||||||
|
key: acc.key,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
params.makeTx(tc)
|
||||||
|
|
||||||
|
proc makeNextTx*(sender: TxSender, tc: BaseTx): Transaction =
|
||||||
|
let
|
||||||
|
acc = sender.getNextAccount()
|
||||||
|
nonce = sender.getNextNonce(acc.address)
|
||||||
|
params = MakeTxParams(
|
||||||
|
chainId: sender.chainId,
|
||||||
|
key: acc.key,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
params.makeTx(tc)
|
||||||
|
|
||||||
|
proc sendNextTx*(sender: TxSender, client: RpcClient, tc: BaseTx): bool =
|
||||||
|
let tx = sender.makeNextTx(tc)
|
||||||
|
let rr = client.sendTransaction(tx)
|
||||||
|
if rr.isErr:
|
||||||
|
error "Unable to send transaction", msg=rr.error
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc sendTx*(sender: TxSender, client: RpcClient, tc: BaseTx, nonce: AccountNonce): bool =
|
||||||
|
let
|
||||||
|
acc = sender.getNextAccount()
|
||||||
|
params = MakeTxParams(
|
||||||
|
chainId: sender.chainId,
|
||||||
|
key: acc.key,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
tx = params.makeTx(tc)
|
||||||
|
|
||||||
|
let rr = client.sendTransaction(tx)
|
||||||
|
if rr.isErr:
|
||||||
|
error "Unable to send transaction", msg=rr.error
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc sendTx*(sender: TxSender, client: RpcClient, tc: BigInitcodeTx, nonce: AccountNonce): bool =
|
||||||
|
let
|
||||||
|
acc = sender.getNextAccount()
|
||||||
|
params = MakeTxParams(
|
||||||
|
chainId: sender.chainId,
|
||||||
|
key: acc.key,
|
||||||
|
nonce: nonce
|
||||||
|
)
|
||||||
|
tx = params.makeTx(tc)
|
||||||
|
|
||||||
|
let rr = client.sendTransaction(tx)
|
||||||
|
if rr.isErr:
|
||||||
|
error "Unable to send transaction", msg=rr.error
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc sendTx*(client: RpcClient, tx: Transaction): bool =
|
||||||
|
let rr = client.sendTransaction(tx)
|
||||||
|
if rr.isErr:
|
||||||
|
error "Unable to send transaction", msg=rr.error
|
||||||
|
return false
|
||||||
|
return true
|
|
@ -1,6 +1,7 @@
|
||||||
import
|
import
|
||||||
std/[options, typetraits, strutils],
|
std/[options, typetraits, strutils],
|
||||||
eth/common,
|
eth/common,
|
||||||
|
stew/byteutils,
|
||||||
web3/ethtypes,
|
web3/ethtypes,
|
||||||
web3/engine_api_types,
|
web3/engine_api_types,
|
||||||
../../../nimbus/beacon/execution_types,
|
../../../nimbus/beacon/execution_types,
|
||||||
|
@ -19,6 +20,7 @@ type
|
||||||
const
|
const
|
||||||
DefaultTimeout* = 60 # seconds
|
DefaultTimeout* = 60 # seconds
|
||||||
DefaultSleep* = 1
|
DefaultSleep* = 1
|
||||||
|
prevRandaoContractAddr* = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
||||||
|
|
||||||
template testCond*(expr: untyped) =
|
template testCond*(expr: untyped) =
|
||||||
if not (expr):
|
if not (expr):
|
||||||
|
@ -85,6 +87,16 @@ template expectStatus*(res, cond: untyped) =
|
||||||
testCond s.status == PayloadExecutionStatus.cond:
|
testCond s.status == PayloadExecutionStatus.cond:
|
||||||
error "Unexpected newPayload status", expect=PayloadExecutionStatus.cond, get=s.status
|
error "Unexpected newPayload status", expect=PayloadExecutionStatus.cond, get=s.status
|
||||||
|
|
||||||
|
template expectStatusEither*(res, cond1, cond2: untyped) =
|
||||||
|
testCond res.isOk:
|
||||||
|
error "Unexpected newPayload error", msg=res.error
|
||||||
|
let s = res.get()
|
||||||
|
testCond s.status == PayloadExecutionStatus.cond1 or s.status == PayloadExecutionStatus.cond2:
|
||||||
|
error "Unexpected newPayload status",
|
||||||
|
expect1=PayloadExecutionStatus.cond1,
|
||||||
|
expect2=PayloadExecutionStatus.cond2,
|
||||||
|
get=s.status
|
||||||
|
|
||||||
template expectWithdrawalsRoot*(res: untyped, h: common.BlockHeader, wdRoot: Option[common.Hash256]) =
|
template expectWithdrawalsRoot*(res: untyped, h: common.BlockHeader, wdRoot: Option[common.Hash256]) =
|
||||||
testCond res.isOk:
|
testCond res.isOk:
|
||||||
error "Unexpected error", msg=res.error
|
error "Unexpected error", msg=res.error
|
||||||
|
|
|
@ -3,7 +3,7 @@ import
|
||||||
withdrawals/wd_block_value_spec,
|
withdrawals/wd_block_value_spec,
|
||||||
withdrawals/wd_max_init_code_spec,
|
withdrawals/wd_max_init_code_spec,
|
||||||
#withdrawals/wd_payload_body_spec,
|
#withdrawals/wd_payload_body_spec,
|
||||||
#withdrawals/wd_reorg_spec,
|
withdrawals/wd_reorg_spec,
|
||||||
withdrawals/wd_sync_spec,
|
withdrawals/wd_sync_spec,
|
||||||
./types,
|
./types,
|
||||||
./test_env
|
./test_env
|
||||||
|
@ -24,7 +24,72 @@ proc specExecute[T](ws: BaseSpec): bool =
|
||||||
|
|
||||||
let wdTestList* = [
|
let wdTestList* = [
|
||||||
#Re-Org tests
|
#Re-Org tests
|
||||||
#[TestDesc(
|
TestDesc(
|
||||||
|
name: "Withdrawals Fork on Block 1 - 8 Block Re-Org, Sync",
|
||||||
|
about: "Tests a 8 block re-org using NewPayload. Re-org does not change withdrawals fork height",
|
||||||
|
run: specExecute[ReorgSpec],
|
||||||
|
spec: ReorgSpec(
|
||||||
|
slotsToSafe: u256(32),
|
||||||
|
slotsToFinalized: u256(64),
|
||||||
|
timeoutSeconds: 300,
|
||||||
|
wdForkHeight: 1, # Genesis is Pre-Withdrawals
|
||||||
|
wdBlockCount: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
||||||
|
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
||||||
|
reOrgBlockCount: 8,
|
||||||
|
reOrgViaSync: true,
|
||||||
|
)),
|
||||||
|
TestDesc(
|
||||||
|
name: "Withdrawals Fork on Block 8 - 10 Block Re-Org Sync",
|
||||||
|
about: " Tests a 10 block re-org using sync",
|
||||||
|
# Re-org does not change withdrawals fork height, but changes
|
||||||
|
# the payload at the height of the fork
|
||||||
|
run: specExecute[ReorgSpec],
|
||||||
|
spec: ReorgSpec(
|
||||||
|
slotsToSafe: u256(32),
|
||||||
|
slotsToFinalized: u256(64),
|
||||||
|
timeoutSeconds: 300,
|
||||||
|
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
||||||
|
wdBlockCount: 8,
|
||||||
|
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
||||||
|
reOrgBlockCount: 10,
|
||||||
|
reOrgViaSync: true,
|
||||||
|
)),
|
||||||
|
TestDesc(
|
||||||
|
name: "Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org Sync",
|
||||||
|
about: "Tests a 10 block re-org using sync",
|
||||||
|
# Sidechain reaches withdrawals fork at a lower block height
|
||||||
|
# than the canonical chain
|
||||||
|
run: specExecute[ReorgSpec],
|
||||||
|
spec: ReorgSpec(
|
||||||
|
slotsToSafe: u256(32),
|
||||||
|
slotsToFinalized: u256(64),
|
||||||
|
timeoutSeconds: 300,
|
||||||
|
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
||||||
|
wdBlockCount: 8,
|
||||||
|
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
||||||
|
reOrgBlockCount: 10,
|
||||||
|
reOrgViaSync: true,
|
||||||
|
sidechaintimeIncrements: 2,
|
||||||
|
)),
|
||||||
|
TestDesc(
|
||||||
|
name: "Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org Sync",
|
||||||
|
about: "Tests a 10 block re-org using sync",
|
||||||
|
# Sidechain reaches withdrawals fork at a higher block height
|
||||||
|
# than the canonical chain
|
||||||
|
run: specExecute[ReorgSpec],
|
||||||
|
spec: ReorgSpec(
|
||||||
|
slotsToSafe: u256(32),
|
||||||
|
slotsToFinalized: u256(64),
|
||||||
|
timeoutSeconds: 300,
|
||||||
|
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
||||||
|
wdBlockCount: 8,
|
||||||
|
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
||||||
|
timeIncrements: 2,
|
||||||
|
reOrgBlockCount: 10,
|
||||||
|
reOrgViaSync: true,
|
||||||
|
sidechaintimeIncrements: 1,
|
||||||
|
)),
|
||||||
|
TestDesc(
|
||||||
name: "Withdrawals Fork on Block 1 - 1 Block Re-Org",
|
name: "Withdrawals Fork on Block 1 - 1 Block Re-Org",
|
||||||
about: "Tests a simple 1 block re-org",
|
about: "Tests a simple 1 block re-org",
|
||||||
run: specExecute[ReorgSpec],
|
run: specExecute[ReorgSpec],
|
||||||
|
@ -52,20 +117,6 @@ let wdTestList* = [
|
||||||
reOrgBlockCount: 8,
|
reOrgBlockCount: 8,
|
||||||
reOrgViaSync: false,
|
reOrgViaSync: false,
|
||||||
)),
|
)),
|
||||||
TestDesc(
|
|
||||||
name: "Withdrawals Fork on Block 1 - 8 Block Re-Org, Sync",
|
|
||||||
about: "Tests a 8 block re-org using NewPayload. Re-org does not change withdrawals fork height",
|
|
||||||
run: specExecute[ReorgSpec],
|
|
||||||
spec: ReorgSpec(
|
|
||||||
slotsToSafe: u256(32),
|
|
||||||
slotsToFinalized: u256(64),
|
|
||||||
timeoutSeconds: 300,
|
|
||||||
wdForkHeight: 1, # Genesis is Pre-Withdrawals
|
|
||||||
wdBlockCount: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
|
||||||
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
|
||||||
reOrgBlockCount: 8,
|
|
||||||
reOrgViaSync: true,
|
|
||||||
)),
|
|
||||||
TestDesc(
|
TestDesc(
|
||||||
name: "Withdrawals Fork on Block 8 - 10 Block Re-Org NewPayload",
|
name: "Withdrawals Fork on Block 8 - 10 Block Re-Org NewPayload",
|
||||||
about: "Tests a 10 block re-org using NewPayload\n" &
|
about: "Tests a 10 block re-org using NewPayload\n" &
|
||||||
|
@ -82,22 +133,6 @@ let wdTestList* = [
|
||||||
reOrgBlockCount: 10,
|
reOrgBlockCount: 10,
|
||||||
reOrgViaSync: false,
|
reOrgViaSync: false,
|
||||||
)),
|
)),
|
||||||
TestDesc(
|
|
||||||
name: "Withdrawals Fork on Block 8 - 10 Block Re-Org Sync",
|
|
||||||
about: " Tests a 10 block re-org using sync",
|
|
||||||
# Re-org does not change withdrawals fork height, but changes
|
|
||||||
# the payload at the height of the fork
|
|
||||||
run: specExecute[ReorgSpec],
|
|
||||||
spec: ReorgSpec(
|
|
||||||
slotsToSafe: u256(32),
|
|
||||||
slotsToFinalized: u256(64),
|
|
||||||
timeoutSeconds: 300,
|
|
||||||
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
|
||||||
wdBlockCount: 8,
|
|
||||||
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
|
||||||
reOrgBlockCount: 10,
|
|
||||||
reOrgViaSync: true,
|
|
||||||
)),
|
|
||||||
TestDesc(
|
TestDesc(
|
||||||
name: "Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org",
|
name: "Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org",
|
||||||
about: "Tests a 10 block re-org using NewPayload",
|
about: "Tests a 10 block re-org using NewPayload",
|
||||||
|
@ -115,23 +150,6 @@ let wdTestList* = [
|
||||||
reOrgViaSync: false,
|
reOrgViaSync: false,
|
||||||
sidechaintimeIncrements: 2,
|
sidechaintimeIncrements: 2,
|
||||||
)),
|
)),
|
||||||
TestDesc(
|
|
||||||
name: "Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org Sync",
|
|
||||||
about: "Tests a 10 block re-org using sync",
|
|
||||||
# Sidechain reaches withdrawals fork at a lower block height
|
|
||||||
# than the canonical chain
|
|
||||||
run: specExecute[ReorgSpec],
|
|
||||||
spec: ReorgSpec(
|
|
||||||
slotsToSafe: u256(32),
|
|
||||||
slotsToFinalized: u256(64),
|
|
||||||
timeoutSeconds: 300,
|
|
||||||
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
|
||||||
wdBlockCount: 8,
|
|
||||||
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
|
||||||
reOrgBlockCount: 10,
|
|
||||||
reOrgViaSync: true,
|
|
||||||
sidechaintimeIncrements: 2,
|
|
||||||
)),
|
|
||||||
TestDesc(
|
TestDesc(
|
||||||
name: "Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org",
|
name: "Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org",
|
||||||
about: "Tests a 10 block re-org using NewPayload",
|
about: "Tests a 10 block re-org using NewPayload",
|
||||||
|
@ -150,24 +168,6 @@ let wdTestList* = [
|
||||||
reOrgViaSync: false,
|
reOrgViaSync: false,
|
||||||
sidechaintimeIncrements: 1,
|
sidechaintimeIncrements: 1,
|
||||||
)),
|
)),
|
||||||
TestDesc(
|
|
||||||
name: "Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org Sync",
|
|
||||||
about: "Tests a 10 block re-org using sync",
|
|
||||||
# Sidechain reaches withdrawals fork at a higher block height
|
|
||||||
# than the canonical chain
|
|
||||||
run: specExecute[ReorgSpec],
|
|
||||||
spec: ReorgSpec(
|
|
||||||
slotsToSafe: u256(32),
|
|
||||||
slotsToFinalized: u256(64),
|
|
||||||
timeoutSeconds: 300,
|
|
||||||
wdForkHeight: 8, # Genesis is Pre-Withdrawals
|
|
||||||
wdBlockCount: 8,
|
|
||||||
wdPerBlock: MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK,
|
|
||||||
timeIncrements: 2,
|
|
||||||
reOrgBlockCount: 10,
|
|
||||||
reOrgViaSync: true,
|
|
||||||
sidechaintimeIncrements: 1,
|
|
||||||
)),]#
|
|
||||||
|
|
||||||
# Sync Tests
|
# Sync Tests
|
||||||
TestDesc(
|
TestDesc(
|
||||||
|
|
|
@ -32,8 +32,8 @@ type
|
||||||
skipBaseVerifications*: bool # For code reuse of the base spec procedure
|
skipBaseVerifications*: bool # For code reuse of the base spec procedure
|
||||||
|
|
||||||
WithdrawalsForBlock = object
|
WithdrawalsForBlock = object
|
||||||
wds: seq[Withdrawal]
|
wds*: seq[Withdrawal]
|
||||||
nextIndex: int
|
nextIndex*: int
|
||||||
|
|
||||||
const
|
const
|
||||||
GenesisTimestamp = 0x1234
|
GenesisTimestamp = 0x1234
|
||||||
|
@ -46,13 +46,13 @@ const
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get the per-block timestamp increments configured for this test
|
# Get the per-block timestamp increments configured for this test
|
||||||
func getBlockTimeIncrements(ws: WDBaseSpec): int =
|
func getBlockTimeIncrements*(ws: WDBaseSpec): int =
|
||||||
if ws.timeIncrements == 0:
|
if ws.timeIncrements == 0:
|
||||||
return 1
|
return 1
|
||||||
ws.timeIncrements
|
ws.timeIncrements
|
||||||
|
|
||||||
# Timestamp delta between genesis and the withdrawals fork
|
# Timestamp delta between genesis and the withdrawals fork
|
||||||
func getWithdrawalsGenesisTimeDelta(ws: WDBaseSpec): int =
|
func getWithdrawalsGenesisTimeDelta*(ws: WDBaseSpec): int =
|
||||||
ws.wdForkHeight * ws.getBlockTimeIncrements()
|
ws.wdForkHeight * ws.getBlockTimeIncrements()
|
||||||
|
|
||||||
# Calculates Shanghai fork timestamp given the amount of blocks that need to be
|
# Calculates Shanghai fork timestamp given the amount of blocks that need to be
|
||||||
|
@ -93,7 +93,7 @@ func addUnconditionalBytecode(g: Genesis, start, stop: UInt256) =
|
||||||
)
|
)
|
||||||
acc = acc + 1
|
acc = acc + 1
|
||||||
|
|
||||||
func getWithdrawableAccountCount(ws: WDBaseSpec):int =
|
func getWithdrawableAccountCount*(ws: WDBaseSpec):int =
|
||||||
if ws.wdAbleAccountCount == 0:
|
if ws.wdAbleAccountCount == 0:
|
||||||
# Withdraw to MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK accounts by default
|
# Withdraw to MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK accounts by default
|
||||||
return MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK
|
return MAINNET_MAX_WITHDRAWAL_COUNT_PER_BLOCK
|
||||||
|
@ -163,7 +163,7 @@ func getGenesis*(ws: WDBaseSpec, param: NetworkParams): NetworkParams =
|
||||||
|
|
||||||
param
|
param
|
||||||
|
|
||||||
func getTransactionCountPerPayload(ws: WDBaseSpec): int =
|
func getTransactionCountPerPayload*(ws: WDBaseSpec): int =
|
||||||
ws.txPerBlock.get(16)
|
ws.txPerBlock.get(16)
|
||||||
|
|
||||||
proc verifyContractsStorage(ws: WDBaseSpec, env: TestEnv): Result[void, string] =
|
proc verifyContractsStorage(ws: WDBaseSpec, env: TestEnv): Result[void, string] =
|
||||||
|
@ -201,11 +201,11 @@ func getPreWithdrawalsBlockCount*(ws: WDBaseSpec): int =
|
||||||
ws.wdForkHeight - 1
|
ws.wdForkHeight - 1
|
||||||
|
|
||||||
# Number of payloads to be produced (pre and post withdrawals) during the entire test
|
# Number of payloads to be produced (pre and post withdrawals) during the entire test
|
||||||
func getTotalPayloadCount(ws: WDBaseSpec): int =
|
func getTotalPayloadCount*(ws: WDBaseSpec): int =
|
||||||
ws.getPreWithdrawalsBlockCount() + ws.wdBlockCount
|
ws.getPreWithdrawalsBlockCount() + ws.wdBlockCount
|
||||||
|
|
||||||
# Generates a list of withdrawals based on current configuration
|
# Generates a list of withdrawals based on current configuration
|
||||||
func generateWithdrawalsForBlock(ws: WDBaseSpec, nextIndex: int, startAccount: UInt256): WithdrawalsForBlock =
|
func generateWithdrawalsForBlock*(ws: WDBaseSpec, nextIndex: int, startAccount: UInt256): WithdrawalsForBlock =
|
||||||
let
|
let
|
||||||
differentAccounts = ws.getWithdrawableAccountCount()
|
differentAccounts = ws.getWithdrawableAccountCount()
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import
|
import
|
||||||
|
std/tables,
|
||||||
stint,
|
stint,
|
||||||
chronos,
|
chronos,
|
||||||
chronicles,
|
chronicles,
|
||||||
|
eth/common,
|
||||||
./wd_base_spec,
|
./wd_base_spec,
|
||||||
|
./wd_history,
|
||||||
../test_env,
|
../test_env,
|
||||||
../engine_client,
|
../engine_client,
|
||||||
../types
|
../types,
|
||||||
|
../../../nimbus/beacon/web3_eth_conv
|
||||||
|
|
||||||
# Withdrawals re-org spec:
|
# Withdrawals re-org spec:
|
||||||
# Specifies a withdrawals test where the withdrawals re-org can happen
|
# Specifies a withdrawals test where the withdrawals re-org can happen
|
||||||
|
@ -13,311 +17,315 @@ import
|
||||||
# withdrawals block.
|
# withdrawals block.
|
||||||
type
|
type
|
||||||
ReorgSpec* = ref object of WDBaseSpec
|
ReorgSpec* = ref object of WDBaseSpec
|
||||||
reOrgBlockCount* : uint64 # How many blocks the re-org will replace, including the head
|
# How many blocks the re-org will replace, including the head
|
||||||
reOrgViaSync* : bool # Whether the client should fetch the sidechain by syncing from the secondary client
|
reOrgBlockCount* : int
|
||||||
sidechainTimeIncrements*: uint64
|
# Whether the client should fetch the sidechain by syncing from the secondary client
|
||||||
|
reOrgViaSync* : bool
|
||||||
|
sidechainTimeIncrements*: int
|
||||||
slotsToSafe* : UInt256
|
slotsToSafe* : UInt256
|
||||||
slotsToFinalized* : UInt256
|
slotsToFinalized* : UInt256
|
||||||
timeoutSeconds* : int
|
timeoutSeconds* : int
|
||||||
|
|
||||||
#[
|
Sidechain = ref object
|
||||||
func (ws *WithdrawalsReorgSpec) GetSidechainSplitHeight() uint64 {
|
startAccount: UInt256
|
||||||
if ws.ReOrgBlockCount > ws.getTotalPayloadCount() {
|
nextIndex : int
|
||||||
panic("invalid payload/re-org configuration")
|
wdHistory : WDHistory
|
||||||
|
sidechain : Table[uint64, ExecutionPayload]
|
||||||
|
payloadId : PayloadID
|
||||||
|
height : uint64
|
||||||
|
attr : Option[PayloadAttributes]
|
||||||
|
|
||||||
return ws.getTotalPayloadCount() + 1 - ws.ReOrgBlockCount
|
Canonical = ref object
|
||||||
|
startAccount: UInt256
|
||||||
|
nextIndex : int
|
||||||
|
|
||||||
func (ws *WithdrawalsReorgSpec) GetSidechainBlockTimeIncrements() uint64 {
|
proc getSidechainSplitHeight(ws: ReorgSpec): int =
|
||||||
if ws.SidechainTimeIncrements == 0 {
|
doAssert(ws.reOrgBlockCount <= ws.getTotalPayloadCount())
|
||||||
|
return ws.getTotalPayloadCount() + 1 - ws.reOrgBlockCount
|
||||||
|
|
||||||
|
proc getSidechainBlockTimeIncrements(ws: ReorgSpec): int=
|
||||||
|
if ws.sidechainTimeIncrements == 0:
|
||||||
return ws.getBlockTimeIncrements()
|
return ws.getBlockTimeIncrements()
|
||||||
|
ws.sidechainTimeIncrements
|
||||||
|
|
||||||
return ws.SidechainTimeIncrements
|
proc getSidechainWdForkHeight(ws: ReorgSpec): int =
|
||||||
|
if ws.getSidechainBlockTimeIncrements() != ws.getBlockTimeIncrements():
|
||||||
func (ws *WithdrawalsReorgSpec) GetSidechainWithdrawalsForkHeight() uint64 {
|
# Block timestamp increments in both chains are different so need to
|
||||||
if ws.getSidechainBlockTimeIncrements() != ws.getBlockTimeIncrements() {
|
# calculate different heights, only if split happens before fork.
|
||||||
# Block timestamp increments in both chains are different so need to calculate different heights, only if split happens before fork
|
|
||||||
if ws.getSidechainSplitHeight() == 0 {
|
|
||||||
# We cannot split by having two different genesis blocks.
|
# We cannot split by having two different genesis blocks.
|
||||||
panic("invalid sidechain split height")
|
doAssert(ws.getSidechainSplitHeight() != 0, "invalid sidechain split height")
|
||||||
|
|
||||||
if ws.getSidechainSplitHeight() <= ws.WithdrawalsForkHeight {
|
if ws.getSidechainSplitHeight() <= ws.wdForkHeight:
|
||||||
# We need to calculate the height of the fork on the sidechain
|
# We need to calculate the height of the fork on the sidechain
|
||||||
sidechainSplitBlockTimestamp := ((ws.getSidechainSplitHeight() - 1) * ws.getBlockTimeIncrements())
|
let sidechainSplitBlocktimestamp = (ws.getSidechainSplitHeight() - 1) * ws.getBlockTimeIncrements()
|
||||||
remainingTime := (ws.getWithdrawalsGenesisTimeDelta() - sidechainSplitBlockTimestamp)
|
let remainingTime = ws.getWithdrawalsGenesisTimeDelta() - sidechainSplitBlocktimestamp
|
||||||
if remainingTime == 0 {
|
if remainingTime == 0 :
|
||||||
return ws.getSidechainSplitHeight()
|
return ws.getSidechainSplitHeight()
|
||||||
|
|
||||||
return ((remainingTime - 1) / ws.SidechainTimeIncrements) + ws.getSidechainSplitHeight()
|
return ((remainingTime - 1) div ws.sidechainTimeIncrements) + ws.getSidechainSplitHeight()
|
||||||
|
|
||||||
return ws.WithdrawalsForkHeight
|
return ws.wdForkHeight
|
||||||
]#
|
|
||||||
|
|
||||||
proc execute*(ws: ReorgSpec, t: TestEnv): bool =
|
proc execute*(ws: ReorgSpec, env: TestEnv): bool =
|
||||||
testCond waitFor t.clMock.waitForTTD()
|
result = true
|
||||||
|
|
||||||
|
testCond waitFor env.clMock.waitForTTD()
|
||||||
|
|
||||||
return true
|
|
||||||
#[
|
|
||||||
# Spawn a secondary client which will produce the sidechain
|
# Spawn a secondary client which will produce the sidechain
|
||||||
secondaryEngine, err := hive_rpc.HiveRPCEngineStarter{}.StartClient(t.T, t.TestContext, t.Genesis, t.ClientParams, t.ClientFiles, t.Engine)
|
let sec = env.addEngine(addToCL = false)
|
||||||
if err != nil {
|
|
||||||
error "Unable to spawn a secondary client: %v", t.TestName, err)
|
|
||||||
}
|
|
||||||
secondaryEngineTest := test.NewTestEngineClient(t, secondaryEngine)
|
|
||||||
# t.clMock.AddEngineClient(secondaryEngine)
|
|
||||||
|
|
||||||
var (
|
var
|
||||||
canonicalStartAccount = big.NewInt(0x1000)
|
canonical = Canonical(
|
||||||
canonicalNextIndex = uint64(0)
|
startAccount: u256(0x1000),
|
||||||
sidechainStartAccount = new(big.Int).SetBit(common.Big0, 160, 1)
|
nextIndex : 0,
|
||||||
sidechainNextIndex = uint64(0)
|
)
|
||||||
sidechainwdHistory = make(wdHistory)
|
sidechain = Sidechain(
|
||||||
sidechain = make(map[uint64]*typ.ExecutableData)
|
startAccount: 1.u256 shl 160,
|
||||||
sidechainPayloadId *beacon.PayloadID
|
nextIndex : 0,
|
||||||
|
wdHistory : WDHistory(),
|
||||||
|
sidechain : initTable[uint64, ExecutionPayload]()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Sidechain withdraws on the max account value range 0xffffffffffffffffffffffffffffffffffffffff
|
# Sidechain withdraws on the max account value range 0xffffffffffffffffffffffffffffffffffffffff
|
||||||
sidechainStartAccount.Sub(sidechainStartAccount, big.NewInt(int64(ws.getWithdrawableAccountCount())+1))
|
sidechain.startAccount -= u256(ws.getWithdrawableAccountCount()+1)
|
||||||
|
|
||||||
t.clMock.ProduceBlocks(int(ws.getPreWithdrawalsBlockCount()+ws.WithdrawalsBlockCount), clmock.BlockProcessCallbacks{
|
let numBlocks = ws.getPreWithdrawalsBlockCount()+ws.wdBlockCount
|
||||||
OnPayloadProducerSelected: proc(): bool =
|
let pbRes = env.clMock.produceBlocks(numBlocks, BlockProcessCallbacks(
|
||||||
t.clMock.NextWithdrawals = nil
|
onPayloadProducerSelected: proc(): bool =
|
||||||
|
env.clMock.nextWithdrawals = none(seq[WithdrawalV1])
|
||||||
|
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.WithdrawalsForkHeight {
|
if env.clMock.currentPayloadNumber >= ws.wdForkHeight.uint64:
|
||||||
# Prepare some withdrawals
|
# Prepare some withdrawals
|
||||||
t.clMock.NextWithdrawals, canonicalNextIndex = ws.GenerateWithdrawalsForBlock(canonicalNextIndex, canonicalStartAccount)
|
let wfb = ws.generateWithdrawalsForBlock(canonical.nextIndex, canonical.startAccount)
|
||||||
ws.wdHistory[t.clMock.CurrentPayloadNumber] = t.clMock.NextWithdrawals
|
env.clMock.nextWithdrawals = some(w3Withdrawals wfb.wds)
|
||||||
}
|
canonical.nextIndex = wfb.nextIndex
|
||||||
|
ws.wdHistory.put(env.clMock.currentPayloadNumber, wfb.wds)
|
||||||
|
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.getSidechainSplitHeight() {
|
if env.clMock.currentPayloadNumber >= ws.getSidechainSplitHeight().uint64:
|
||||||
# We have split
|
# We have split
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.getSidechainWithdrawalsForkHeight() {
|
if env.clMock.currentPayloadNumber >= ws.getSidechainWdForkHeight().uint64:
|
||||||
# And we are past the withdrawals fork on the sidechain
|
# And we are past the withdrawals fork on the sidechain
|
||||||
sidechainwdHistory[t.clMock.CurrentPayloadNumber], sidechainNextIndex = ws.GenerateWithdrawalsForBlock(sidechainNextIndex, sidechainStartAccount)
|
let wfb = ws.generateWithdrawalsForBlock(sidechain.nextIndex, sidechain.startAccount)
|
||||||
} # else nothing to do
|
sidechain.wdHistory.put(env.clMock.currentPayloadNumber, wfb.wds)
|
||||||
} else {
|
sidechain.nextIndex = wfb.nextIndex
|
||||||
# We have not split
|
else:
|
||||||
sidechainwdHistory[t.clMock.CurrentPayloadNumber] = t.clMock.NextWithdrawals
|
if env.clMock.nextWithdrawals.isSome:
|
||||||
sidechainNextIndex = canonicalNextIndex
|
let wds = ethWithdrawals env.clMock.nextWithdrawals.get()
|
||||||
}
|
sidechain.wdHistory.put(env.clMock.currentPayloadNumber, wds)
|
||||||
|
sidechain.nextIndex = canonical.nextIndex
|
||||||
|
|
||||||
},
|
return true
|
||||||
OnRequestNextPayload: proc(): bool =
|
,
|
||||||
|
onRequestNextPayload: proc(): bool =
|
||||||
# Send transactions to be included in the payload
|
# Send transactions to be included in the payload
|
||||||
txs, err := helper.SendNextTransactions(
|
let txs = env.makeTxs(
|
||||||
t.TestContext,
|
BaseTx(
|
||||||
t.clMock.NextBlockProducer,
|
recipient: some(prevRandaoContractAddr),
|
||||||
&helper.BaseTransactionCreator{
|
amount: 1.u256,
|
||||||
Recipient: &globals.PrevRandaoContractAddr,
|
txType: ws.txType,
|
||||||
Amount: common.Big1,
|
gasLimit: 75000.GasInt,
|
||||||
Payload: nil,
|
),
|
||||||
TxType: t.TestTransactionType,
|
ws.getTransactionCountPerPayload()
|
||||||
GasLimit: 75000,
|
|
||||||
},
|
|
||||||
ws.getTransactionCountPerPayload(),
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
error "Error trying to send transactions: %v", t.TestName, err)
|
testCond env.sendTxs(env.clMock.nextBlockProducer, txs):
|
||||||
}
|
error "Error trying to send transaction"
|
||||||
|
|
||||||
# Error will be ignored here since the tx could have been already relayed
|
# Error will be ignored here since the tx could have been already relayed
|
||||||
secondaryEngine.SendTransactions(t.TestContext, txs...)
|
discard env.sendTxs(sec, txs)
|
||||||
|
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.getSidechainSplitHeight() {
|
if env.clMock.currentPayloadNumber >= ws.getSidechainSplitHeight().uint64:
|
||||||
# Also request a payload from the sidechain
|
# Also request a payload from the sidechain
|
||||||
fcU := beacon.ForkchoiceStateV1{
|
var fcState = ForkchoiceStateV1(
|
||||||
HeadBlockHash: t.clMock.latestForkchoice.HeadBlockHash,
|
headBlockHash: env.clMock.latestForkchoice.headBlockHash,
|
||||||
}
|
)
|
||||||
|
|
||||||
if t.clMock.CurrentPayloadNumber > ws.getSidechainSplitHeight() {
|
if env.clMock.currentPayloadNumber > ws.getSidechainSplitHeight().uint64:
|
||||||
if lastSidePayload, ok := sidechain[t.clMock.CurrentPayloadNumber-1]; !ok {
|
let lastSidePayload = sidechain.sidechain[env.clMock.currentPayloadNumber-1]
|
||||||
panic("sidechain payload not found")
|
fcState.headBlockHash = lastSidePayload.blockHash
|
||||||
} else {
|
|
||||||
fcU.HeadBlockHash = lastSidePayload.BlockHash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var version int
|
var attr = PayloadAttributes(
|
||||||
pAttributes := typ.PayloadAttributes{
|
prevRandao: env.clMock.latestPayloadAttributes.prevRandao,
|
||||||
Random: t.clMock.latestPayloadAttributes.Random,
|
suggestedFeeRecipient: env.clMock.latestPayloadAttributes.suggestedFeeRecipient,
|
||||||
SuggestedFeeRecipient: t.clMock.latestPayloadAttributes.SuggestedFeeRecipient,
|
)
|
||||||
}
|
|
||||||
if t.clMock.CurrentPayloadNumber > ws.getSidechainSplitHeight() {
|
if env.clMock.currentPayloadNumber > ws.getSidechainSplitHeight().uint64:
|
||||||
pAttributes.Timestamp = sidechain[t.clMock.CurrentPayloadNumber-1].Timestamp + uint64(ws.getSidechainBlockTimeIncrements())
|
attr.timestamp = w3Qty(sidechain.sidechain[env.clMock.currentPayloadNumber-1].timestamp, ws.getSidechainBlockTimeIncrements())
|
||||||
} else if t.clMock.CurrentPayloadNumber == ws.getSidechainSplitHeight() {
|
elif env.clMock.currentPayloadNumber == ws.getSidechainSplitHeight().uint64:
|
||||||
pAttributes.Timestamp = t.clMock.latestHeader.Time + uint64(ws.getSidechainBlockTimeIncrements())
|
attr.timestamp = w3Qty(env.clMock.latestHeader.timestamp, ws.getSidechainBlockTimeIncrements())
|
||||||
} else {
|
else:
|
||||||
pAttributes.Timestamp = t.clMock.latestPayloadAttributes.Timestamp
|
attr.timestamp = env.clMock.latestPayloadAttributes.timestamp
|
||||||
}
|
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.getSidechainWithdrawalsForkHeight() {
|
if env.clMock.currentPayloadNumber >= ws.getSidechainwdForkHeight().uint64:
|
||||||
# Withdrawals
|
# Withdrawals
|
||||||
version = 2
|
let rr = sidechain.wdHistory.get(env.clMock.currentPayloadNumber)
|
||||||
pAttributes.Withdrawals = sidechainwdHistory[t.clMock.CurrentPayloadNumber]
|
testCond rr.isOk:
|
||||||
} else {
|
error "sidechain wd", msg=rr.error
|
||||||
# No withdrawals
|
|
||||||
version = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
info "Requesting sidechain payload %d: %v", t.TestName, t.clMock.CurrentPayloadNumber, pAttributes)
|
attr.withdrawals = some(w3Withdrawals rr.get)
|
||||||
|
|
||||||
r := secondaryEngineTest.forkchoiceUpdated(&fcU, &pAttributes, version)
|
info "Requesting sidechain payload",
|
||||||
|
number=env.clMock.currentPayloadNumber
|
||||||
|
|
||||||
|
sidechain.attr = some(attr)
|
||||||
|
let r = sec.client.forkchoiceUpdated(fcState, attr)
|
||||||
r.expectNoError()
|
r.expectNoError()
|
||||||
r.expectPayloadStatus(test.Valid)
|
r.testFCU(valid)
|
||||||
if r.Response.PayloadID == nil {
|
testCond r.get().payloadID.isSome:
|
||||||
error "Unable to get a payload ID on the sidechain", t.TestName)
|
error "Unable to get a payload ID on the sidechain"
|
||||||
}
|
sidechain.payloadId = r.get().payloadID.get()
|
||||||
sidechainPayloadId = r.Response.PayloadID
|
|
||||||
}
|
return true
|
||||||
},
|
,
|
||||||
OnGetPayload: proc(): bool =
|
onGetPayload: proc(): bool =
|
||||||
var (
|
var
|
||||||
version int
|
payload: ExecutionPayload
|
||||||
payload *typ.ExecutableData
|
|
||||||
)
|
if env.clMock.latestPayloadBuilt.blockNumber.uint64 >= ws.getSidechainSplitHeight().uint64:
|
||||||
if t.clMock.CurrentPayloadNumber >= ws.getSidechainWithdrawalsForkHeight() {
|
|
||||||
version = 2
|
|
||||||
} else {
|
|
||||||
version = 1
|
|
||||||
}
|
|
||||||
if t.clMock.latestPayloadBuilt.Number >= ws.getSidechainSplitHeight() {
|
|
||||||
# This payload is built by the secondary client, hence need to manually fetch it here
|
# This payload is built by the secondary client, hence need to manually fetch it here
|
||||||
r := secondaryEngineTest.getPayload(sidechainPayloadId, version)
|
doAssert(sidechain.attr.isSome)
|
||||||
|
let version = sidechain.attr.get().version
|
||||||
|
let r = sec.client.getPayload(sidechain.payloadId, version)
|
||||||
r.expectNoError()
|
r.expectNoError()
|
||||||
payload = &r.Payload
|
payload = r.get().executionPayload
|
||||||
sidechain[payload.Number] = payload
|
sidechain.sidechain[payload.blockNumber.uint64] = payload
|
||||||
} else {
|
else:
|
||||||
# This block is part of both chains, simply forward it to the secondary client
|
# This block is part of both chains, simply forward it to the secondary client
|
||||||
payload = &t.clMock.latestPayloadBuilt
|
payload = env.clMock.latestPayloadBuilt
|
||||||
}
|
|
||||||
r := secondaryEngineTest.newPayload(payload, nil, nil, version)
|
let r = sec.client.newPayload(payload, payload.version)
|
||||||
r.expectStatus(test.Valid)
|
r.expectStatus(valid)
|
||||||
p := secondaryEngineTest.forkchoiceUpdated(
|
|
||||||
&beacon.ForkchoiceStateV1{
|
let fcState = ForkchoiceStateV1(
|
||||||
HeadBlockHash: payload.BlockHash,
|
headBlockHash: payload.blockHash,
|
||||||
},
|
|
||||||
nil,
|
|
||||||
version,
|
|
||||||
)
|
)
|
||||||
p.expectPayloadStatus(test.Valid)
|
let p = sec.client.forkchoiceUpdated(payload.version, fcState)
|
||||||
},
|
p.testFCU(valid)
|
||||||
})
|
return true
|
||||||
|
))
|
||||||
|
testCond pbRes
|
||||||
|
|
||||||
sidechainHeight := t.clMock.latestExecutedPayload.Number
|
sidechain.height = env.clMock.latestExecutedPayload.blockNumber.uint64
|
||||||
|
|
||||||
if ws.WithdrawalsForkHeight < ws.getSidechainWithdrawalsForkHeight() {
|
if ws.wdForkHeight < ws.getSidechainwdForkHeight():
|
||||||
# This means the canonical chain forked before the sidechain.
|
# This means the canonical chain forked before the sidechain.
|
||||||
# Therefore we need to produce more sidechain payloads to reach
|
# Therefore we need to produce more sidechain payloads to reach
|
||||||
# at least`ws.WithdrawalsBlockCount` withdrawals payloads produced on
|
# at least`ws.WithdrawalsBlockCount` withdrawals payloads produced on
|
||||||
# the sidechain.
|
# the sidechain.
|
||||||
for i := uint64(0); i < ws.getSidechainWithdrawalsForkHeight()-ws.WithdrawalsForkHeight; i++ {
|
let height = ws.getSidechainwdForkHeight()-ws.wdForkHeight
|
||||||
sidechainwdHistory[sidechainHeight+1], sidechainNextIndex = ws.GenerateWithdrawalsForBlock(sidechainNextIndex, sidechainStartAccount)
|
for i in 0..<height:
|
||||||
pAttributes := typ.PayloadAttributes{
|
let
|
||||||
Timestamp: sidechain[sidechainHeight].Timestamp + ws.getSidechainBlockTimeIncrements(),
|
wfb = ws.generateWithdrawalsForBlock(sidechain.nextIndex, sidechain.startAccount)
|
||||||
Random: t.clMock.latestPayloadAttributes.Random,
|
|
||||||
SuggestedFeeRecipient: t.clMock.latestPayloadAttributes.SuggestedFeeRecipient,
|
sidechain.wdHistory.put(sidechain.height+1, wfb.wds)
|
||||||
Withdrawals: sidechainwdHistory[sidechainHeight+1],
|
sidechain.nextIndex = wfb.nextIndex
|
||||||
}
|
|
||||||
r := secondaryEngineTest.forkchoiceUpdatedV2(&beacon.ForkchoiceStateV1{
|
let wds = sidechain.wdHistory.get(sidechain.height+1).valueOr:
|
||||||
HeadBlockHash: sidechain[sidechainHeight].BlockHash,
|
echo "get wd history error ", error
|
||||||
}, &pAttributes)
|
return false
|
||||||
r.expectPayloadStatus(test.Valid)
|
|
||||||
time.Sleep(time.Second)
|
let
|
||||||
p := secondaryEngineTest.getPayloadV2(r.Response.PayloadID)
|
attr = PayloadAttributes(
|
||||||
p.expectNoError()
|
timestamp: w3Qty(sidechain.sidechain[sidechain.height].timestamp, ws.getSidechainBlockTimeIncrements()),
|
||||||
s := secondaryEngineTest.newPayloadV2(&p.Payload)
|
prevRandao: env.clMock.latestPayloadAttributes.prevRandao,
|
||||||
s.expectStatus(test.Valid)
|
suggestedFeeRecipient: env.clMock.latestPayloadAttributes.suggestedFeeRecipient,
|
||||||
q := secondaryEngineTest.forkchoiceUpdatedV2(
|
withdrawals: some(w3Withdrawals wds),
|
||||||
&beacon.ForkchoiceStateV1{
|
|
||||||
HeadBlockHash: p.Payload.BlockHash,
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
)
|
||||||
q.expectPayloadStatus(test.Valid)
|
fcState = ForkchoiceStateV1(
|
||||||
sidechainHeight++
|
headBlockHash: sidechain.sidechain[sidechain.height].blockHash,
|
||||||
sidechain[sidechainHeight] = &p.Payload
|
)
|
||||||
}
|
|
||||||
}
|
let r = sec.client.forkchoiceUpdatedV2(fcState, some(attr))
|
||||||
|
r.testFCU(valid)
|
||||||
|
|
||||||
|
let p = sec.client.getPayloadV2(r.get().payloadID.get)
|
||||||
|
p.expectNoError()
|
||||||
|
|
||||||
|
let z = p.get()
|
||||||
|
let s = sec.client.newPayloadV2(z.executionPayload)
|
||||||
|
s.expectStatus(valid)
|
||||||
|
|
||||||
|
let fs = ForkchoiceStateV1(headBlockHash: z.executionPayload.blockHash)
|
||||||
|
|
||||||
|
let q = sec.client.forkchoiceUpdatedV2(fs)
|
||||||
|
q.testFCU(valid)
|
||||||
|
|
||||||
|
inc sidechain.height
|
||||||
|
sidechain.sidechain[sidechain.height] = executionPayload(z.executionPayload)
|
||||||
|
|
||||||
# Check the withdrawals on the latest
|
# Check the withdrawals on the latest
|
||||||
ws.wdHistory.VerifyWithdrawals(
|
let res = ws.wdHistory.verifyWithdrawals(sidechain.height, none(UInt256), env.client)
|
||||||
sidechainHeight,
|
testCond res.isOk
|
||||||
nil,
|
|
||||||
t.TestEngine,
|
|
||||||
)
|
|
||||||
|
|
||||||
if ws.ReOrgViaSync {
|
if ws.reOrgViaSync:
|
||||||
# Send latest sidechain payload as NewPayload + FCU and wait for sync
|
# Send latest sidechain payload as NewPayload + FCU and wait for sync
|
||||||
loop:
|
let
|
||||||
for {
|
payload = sidechain.sidechain[sidechain.height]
|
||||||
r := t.rpcClient.newPayloadV2(sidechain[sidechainHeight])
|
sideHash = sidechain.sidechain[sidechain.height].blockHash
|
||||||
|
sleep = DefaultSleep
|
||||||
|
period = chronos.seconds(sleep)
|
||||||
|
|
||||||
|
var loop = 0
|
||||||
|
if ws.timeoutSeconds == 0:
|
||||||
|
ws.timeoutSeconds = DefaultTimeout
|
||||||
|
|
||||||
|
while loop < ws.timeoutSeconds:
|
||||||
|
let r = env.client.newPayloadV2(payload.V2)
|
||||||
r.expectNoError()
|
r.expectNoError()
|
||||||
p := t.rpcClient.forkchoiceUpdatedV2(
|
let fcState = ForkchoiceStateV1(headBlockHash: sideHash)
|
||||||
&beacon.ForkchoiceStateV1{
|
let p = env.client.forkchoiceUpdatedV2(fcState)
|
||||||
HeadBlockHash: sidechain[sidechainHeight].BlockHash,
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
p.expectNoError()
|
p.expectNoError()
|
||||||
if p.Response.PayloadStatus.Status == test.Invalid {
|
|
||||||
error "Primary client invalidated side chain", t.TestName)
|
let status = p.get().payloadStatus.status
|
||||||
}
|
if status == PayloadExecutionStatus.invalid:
|
||||||
select {
|
error "Primary client invalidated side chain"
|
||||||
case <-t.TimeoutContext.Done():
|
return false
|
||||||
error "Timeout waiting for sync", t.TestName)
|
|
||||||
case <-time.After(time.Second):
|
var header: common.BlockHeader
|
||||||
b := t.rpcClient.BlockByNumber(nil)
|
let b = env.client.latestHeader(header)
|
||||||
if b.Block.Hash() == sidechain[sidechainHeight].BlockHash {
|
testCond b.isOk
|
||||||
|
if header.blockHash == ethHash(sidehash):
|
||||||
# sync successful
|
# sync successful
|
||||||
break loop
|
break
|
||||||
}
|
|
||||||
}
|
waitFor sleepAsync(period)
|
||||||
}
|
loop += sleep
|
||||||
} else {
|
else:
|
||||||
# Send all payloads one by one to the primary client
|
# Send all payloads one by one to the primary client
|
||||||
for payloadNumber := ws.getSidechainSplitHeight(); payloadNumber <= sidechainHeight; payloadNumber++ {
|
var payloadNumber = ws.getSidechainSplitHeight()
|
||||||
payload, ok := sidechain[payloadNumber]
|
while payloadNumber.uint64 <= sidechain.height:
|
||||||
if !ok {
|
let payload = sidechain.sidechain[payloadNumber.uint64]
|
||||||
error "Invalid payload %d requested.", t.TestName, payloadNumber)
|
var version = Version.V1
|
||||||
}
|
if payloadNumber >= ws.getSidechainwdForkHeight():
|
||||||
var version int
|
version = Version.V2
|
||||||
if payloadNumber >= ws.getSidechainWithdrawalsForkHeight() {
|
|
||||||
version = 2
|
info "Sending sidechain",
|
||||||
} else {
|
payloadNumber,
|
||||||
version = 1
|
hash=payload.blockHash.short,
|
||||||
}
|
parentHash=payload.parentHash.short
|
||||||
info "Sending sidechain payload %d, hash=%s, parent=%s", t.TestName, payloadNumber, payload.BlockHash, payload.ParentHash)
|
|
||||||
r := t.rpcClient.newPayload(payload, nil, nil, version)
|
let r = env.client.newPayload(payload, version)
|
||||||
r.expectStatusEither(test.Valid, test.Accepted)
|
r.expectStatusEither(valid, accepted)
|
||||||
p := t.rpcClient.forkchoiceUpdated(
|
|
||||||
&beacon.ForkchoiceStateV1{
|
let fcState = ForkchoiceStateV1(headBlockHash: payload.blockHash)
|
||||||
HeadBlockHash: payload.BlockHash,
|
let p = env.client.forkchoiceUpdated(version, fcState)
|
||||||
},
|
p.testFCU(valid)
|
||||||
nil,
|
inc payloadNumber
|
||||||
version,
|
|
||||||
)
|
|
||||||
p.expectPayloadStatus(test.Valid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify withdrawals changed
|
# Verify withdrawals changed
|
||||||
sidechainwdHistory.VerifyWithdrawals(
|
let r2 = sidechain.wdHistory.verifyWithdrawals(sidechain.height, none(UInt256), env.client)
|
||||||
sidechainHeight,
|
testCond r2.isOk
|
||||||
nil,
|
|
||||||
t.TestEngine,
|
|
||||||
)
|
|
||||||
# Verify all balances of accounts in the original chain didn't increase
|
# Verify all balances of accounts in the original chain didn't increase
|
||||||
# after the fork.
|
# after the fork.
|
||||||
# We are using different accounts credited between the canonical chain
|
# We are using different accounts credited between the canonical chain
|
||||||
# and the fork.
|
# and the fork.
|
||||||
# We check on `latest`.
|
# We check on `latest`.
|
||||||
ws.wdHistory.VerifyWithdrawals(
|
let r3 = ws.wdHistory.verifyWithdrawals(uint64(ws.wdForkHeight-1), none(UInt256), env.client)
|
||||||
ws.WithdrawalsForkHeight-1,
|
testCond r3.isOk
|
||||||
nil,
|
|
||||||
t.TestEngine,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Re-Org back to the canonical chain
|
# Re-Org back to the canonical chain
|
||||||
r := t.rpcClient.forkchoiceUpdatedV2(&beacon.ForkchoiceStateV1{
|
let fcState = ForkchoiceStateV1(headBlockHash: env.clMock.latestPayloadBuilt.blockHash)
|
||||||
HeadBlockHash: t.clMock.latestPayloadBuilt.BlockHash,
|
let r = env.client.forkchoiceUpdatedV2(fcState)
|
||||||
}, nil)
|
r.testFCU(valid)
|
||||||
r.expectPayloadStatus(test.Valid)
|
|
||||||
]#
|
|
||||||
|
|
|
@ -52,6 +52,11 @@ type
|
||||||
Option[PayloadAttributesV2] |
|
Option[PayloadAttributesV2] |
|
||||||
Option[PayloadAttributesV3]
|
Option[PayloadAttributesV3]
|
||||||
|
|
||||||
|
GetPayloadResponse* = object
|
||||||
|
executionPayload*: ExecutionPayload
|
||||||
|
blockValue*: Option[UInt256]
|
||||||
|
blobsBundle*: Option[BlobsBundleV1]
|
||||||
|
|
||||||
Version* {.pure.} = enum
|
Version* {.pure.} = enum
|
||||||
V1
|
V1
|
||||||
V2
|
V2
|
||||||
|
@ -59,20 +64,26 @@ type
|
||||||
|
|
||||||
func version*(payload: ExecutionPayload): Version =
|
func version*(payload: ExecutionPayload): Version =
|
||||||
if payload.blobGasUsed.isSome and payload.excessBlobGas.isSome:
|
if payload.blobGasUsed.isSome and payload.excessBlobGas.isSome:
|
||||||
return Version.V3
|
Version.V3
|
||||||
|
elif payload.withdrawals.isSome:
|
||||||
if payload.withdrawals.isSome:
|
Version.V2
|
||||||
return Version.V2
|
else:
|
||||||
|
|
||||||
Version.V1
|
Version.V1
|
||||||
|
|
||||||
func version*(attr: PayloadAttributes): Version =
|
func version*(attr: PayloadAttributes): Version =
|
||||||
if attr.parentBeaconBlockRoot.isSome:
|
if attr.parentBeaconBlockRoot.isSome:
|
||||||
return Version.V3
|
Version.V3
|
||||||
|
elif attr.withdrawals.isSome:
|
||||||
if attr.withdrawals.isSome:
|
Version.V2
|
||||||
return Version.V2
|
else:
|
||||||
|
Version.V1
|
||||||
|
|
||||||
|
func version*(res: GetPayloadResponse): Version =
|
||||||
|
if res.blobsBundle.isSome:
|
||||||
|
Version.V3
|
||||||
|
elif res.blockValue.isSome:
|
||||||
|
Version.V2
|
||||||
|
else:
|
||||||
Version.V1
|
Version.V1
|
||||||
|
|
||||||
func V1V2*(attr: PayloadAttributes): PayloadAttributesV1OrV2 =
|
func V1V2*(attr: PayloadAttributes): PayloadAttributesV1OrV2 =
|
||||||
|
@ -107,6 +118,22 @@ func V3*(attr: PayloadAttributes): PayloadAttributesV3 =
|
||||||
parentBeaconBlockRoot: attr.parentBeaconBlockRoot.get
|
parentBeaconBlockRoot: attr.parentBeaconBlockRoot.get
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func V1*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV1] =
|
||||||
|
if attr.isNone:
|
||||||
|
return none(PayloadAttributesV1)
|
||||||
|
some(attr.get.V1)
|
||||||
|
|
||||||
|
when false:
|
||||||
|
func V2*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV2] =
|
||||||
|
if attr.isNone:
|
||||||
|
return none(PayloadAttributesV2)
|
||||||
|
some(attr.get.V2)
|
||||||
|
|
||||||
|
func V3*(attr: Option[PayloadAttributes]): Option[PayloadAttributesV3] =
|
||||||
|
if attr.isNone:
|
||||||
|
return none(PayloadAttributesV3)
|
||||||
|
some(attr.get.V3)
|
||||||
|
|
||||||
func payloadAttributes*(attr: PayloadAttributesV1): PayloadAttributes =
|
func payloadAttributes*(attr: PayloadAttributesV1): PayloadAttributes =
|
||||||
PayloadAttributes(
|
PayloadAttributes(
|
||||||
timestamp: attr.timestamp,
|
timestamp: attr.timestamp,
|
||||||
|
@ -308,3 +335,19 @@ func executionPayload*(p: ExecutionPayloadV1OrV2): ExecutionPayload =
|
||||||
transactions: p.transactions,
|
transactions: p.transactions,
|
||||||
withdrawals: p.withdrawals
|
withdrawals: p.withdrawals
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func V1*(res: GetPayloadResponse): ExecutionPayloadV1 =
|
||||||
|
res.executionPayload.V1
|
||||||
|
|
||||||
|
func V2*(res: GetPayloadResponse): GetPayloadV2Response =
|
||||||
|
GetPayloadV2Response(
|
||||||
|
executionPayload: res.executionPayload.V1V2,
|
||||||
|
blockValue: res.blockValue.get
|
||||||
|
)
|
||||||
|
|
||||||
|
func V3*(res: GetPayloadResponse): GetPayloadV3Response =
|
||||||
|
GetPayloadV3Response(
|
||||||
|
executionPayload: res.executionPayload.V3,
|
||||||
|
blockValue: res.blockValue.get,
|
||||||
|
blobsBundle: res.blobsBundle.get
|
||||||
|
)
|
||||||
|
|
|
@ -21,7 +21,7 @@ const
|
||||||
# maxTrackedHeaders is the maximum number of executed payloads the execution
|
# maxTrackedHeaders is the maximum number of executed payloads the execution
|
||||||
# engine tracks before evicting old ones. Ideally we should only ever track
|
# engine tracks before evicting old ones. Ideally we should only ever track
|
||||||
# the latest one; but have a slight wiggle room for non-ideal conditions.
|
# the latest one; but have a slight wiggle room for non-ideal conditions.
|
||||||
MaxTrackedHeaders = 10
|
MaxTrackedHeaders = 96
|
||||||
|
|
||||||
type
|
type
|
||||||
QueueItem[T] = object
|
QueueItem[T] = object
|
||||||
|
|
|
@ -168,6 +168,9 @@ func w3Qty*(x: common.EthTime): Web3Quantity =
|
||||||
func w3Qty*(x: common.EthTime, y: int): Web3Quantity =
|
func w3Qty*(x: common.EthTime, y: int): Web3Quantity =
|
||||||
Web3Quantity(x.toUnix + y.int64)
|
Web3Quantity(x.toUnix + y.int64)
|
||||||
|
|
||||||
|
func w3Qty*(x: Web3Quantity, y: int): Web3Quantity =
|
||||||
|
Web3Quantity(x.uint64 + y.uint64)
|
||||||
|
|
||||||
func w3Qty*(x: Option[uint64]): Option[Web3Quantity] =
|
func w3Qty*(x: Option[uint64]): Option[Web3Quantity] =
|
||||||
if x.isNone: none(Web3Quantity)
|
if x.isNone: none(Web3Quantity)
|
||||||
else: some(Web3Quantity x.get)
|
else: some(Web3Quantity x.get)
|
||||||
|
|
|
@ -114,12 +114,17 @@ proc txFeesCovered(xp: TxPoolRef; item: TxItemRef): bool =
|
||||||
return false
|
return false
|
||||||
true
|
true
|
||||||
|
|
||||||
|
import stew/byteutils
|
||||||
|
import ../../../utils/debug
|
||||||
|
|
||||||
proc txCostInBudget(xp: TxPoolRef; item: TxItemRef): bool =
|
proc txCostInBudget(xp: TxPoolRef; item: TxItemRef): bool =
|
||||||
## Check whether the worst case expense is covered by the price budget,
|
## Check whether the worst case expense is covered by the price budget,
|
||||||
let
|
let
|
||||||
balance = xp.chain.getBalance(item.sender)
|
balance = xp.chain.getBalance(item.sender)
|
||||||
gasCost = item.tx.gasCost
|
gasCost = item.tx.gasCost
|
||||||
if balance < gasCost:
|
if balance < gasCost:
|
||||||
|
debugEcho "nonce: ", item.tx.nonce, " ", balance, " ", gasCost, " ", item.sender.toHex
|
||||||
|
debugEcho debug(item.tx)
|
||||||
debug "invalid tx: not enough cash for gas",
|
debug "invalid tx: not enough cash for gas",
|
||||||
available = balance,
|
available = balance,
|
||||||
require = gasCost
|
require = gasCost
|
||||||
|
|
|
@ -18,7 +18,6 @@ import
|
||||||
".."/[protocol, sync_desc],
|
".."/[protocol, sync_desc],
|
||||||
./worker_desc,
|
./worker_desc,
|
||||||
./skeleton_main,
|
./skeleton_main,
|
||||||
./skeleton_utils,
|
|
||||||
./beacon_impl
|
./beacon_impl
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
|
|
Loading…
Reference in New Issue