284 lines
7.9 KiB
Nim
Raw Normal View History

import
std/[os, times, math],
2022-12-02 11:39:12 +07:00
eth/keys,
eth/p2p as eth_p2p,
stew/[results, byteutils],
json_rpc/[rpcserver, rpcclient],
../../../nimbus/[
config,
constants,
transaction,
2022-12-02 11:39:12 +07:00
core/sealer,
core/chain,
core/tx_pool,
core/block_import,
rpc,
sync/protocol,
2022-12-02 11:39:12 +07:00
rpc/merge/merger,
common
],
../../../tests/test_helpers,
"."/[clmock, engine_client]
export
2023-08-21 09:08:54 +07:00
common, times,
2022-12-02 11:39:12 +07:00
results, constants,
2023-08-21 09:08:54 +07:00
clmock, engine_client
type
EthBlockHeader* = common.BlockHeader
TestEnv* = ref object
conf*: NimbusConf
ctx: EthContext
ethNode: EthereumNode
2022-12-02 11:39:12 +07:00
com: CommonRef
chainRef: ChainRef
rpcServer: RpcHttpServer
sealingEngine: SealingEngineRef
rpcClient*: RpcHttpClient
gHeader*: EthBlockHeader
ttd*: DifficultyInt
clMock*: CLMocker
2022-06-13 16:42:01 +07:00
vaultKey*: PrivateKey
2022-06-17 07:53:33 +07:00
tx*: Transaction
2023-08-21 09:08:54 +07:00
nonce*: uint64
BaseTx* = object of RootObj
recipient*: Option[EthAddress]
gasLimit* : GasInt
amount* : UInt256
payload* : seq[byte]
txType* : Option[TxType]
2023-08-21 09:08:54 +07:00
BigInitcodeTx* = object of BaseTx
initcodeLength*: int
padByte* : uint8
initcode* : seq[byte]
const
2023-08-21 09:08:54 +07:00
baseFolder = "hive_integration/nodocker/engine"
genesisFile = baseFolder / "init/genesis.json"
sealerKey = baseFolder / "init/sealer.key"
2022-06-17 07:53:33 +07:00
chainFolder = baseFolder / "chains"
# This is the account that sends vault funding transactions.
vaultAccountAddr* = hexToByteArray[20]("0xcf49fda3be353c69b41ed96333cd24302da4556f")
vaultKeyHex = "63b508a03c3b5937ceb903af8b1b0c191012ef6eb7e9c3fb7afa94e5d214d376"
jwtSecret = "0x7365637265747365637265747365637265747365637265747365637265747365"
proc setupELClient*(t: TestEnv, chainFile: string, enableAuth: bool) =
2022-06-17 07:53:33 +07:00
if chainFile.len > 0:
# disable clique if we are using PoW chain
2022-12-02 11:39:12 +07:00
t.conf.networkParams.config.consensusType = ConsensusType.POW
2022-06-17 07:53:33 +07:00
t.ctx = newEthContext()
let res = t.ctx.am.importPrivateKey(sealerKey)
if res.isErr:
echo res.error()
quit(QuitFailure)
t.ethNode = setupEthNode(t.conf, t.ctx, eth)
2022-12-02 11:39:12 +07:00
t.com = CommonRef.new(
Unified database frontend integration (#1670) * Nimbus folder environment update details: * Integrated `CoreDbRef` for the sources in the `nimbus` sub-folder. * The `nimbus` program does not compile yet as it needs the updates in the parallel `stateless` sub-folder. * Stateless environment update details: * Integrated `CoreDbRef` for the sources in the `stateless` sub-folder. * The `nimbus` program compiles now. * Premix environment update details: * Integrated `CoreDbRef` for the sources in the `premix` sub-folder. * Fluffy environment update details: * Integrated `CoreDbRef` for the sources in the `fluffy` sub-folder. * Tools environment update details: * Integrated `CoreDbRef` for the sources in the `tools` sub-folder. * Nodocker environment update details: * Integrated `CoreDbRef` for the sources in the `hive_integration/nodocker` sub-folder. * Tests environment update details: * Integrated `CoreDbRef` for the sources in the `tests` sub-folder. * The unit tests compile and run cleanly now. * Generalise `CoreDbRef` to any `select_backend` supported database why: Generalisation was just missed due to overcoming some compiler oddity which was tied to rocksdb for testing. * Suppress compiler warning for `newChainDB()` why: Warning was added to this function which must be wrapped so that any `CatchableError` is re-raised as `Defect`. * Split off persistent `CoreDbRef` constructor into separate file why: This allows to compile a memory only database version without linking the backend library. * Use memory `CoreDbRef` database by default detail: Persistent DB constructor needs to import `db/core_db/persistent why: Most tests use memory DB anyway. This avoids linking `-lrocksdb` or any other backend by default. * fix `toLegacyBackend()` availability check why: got garbled after memory/persistent split. * Clarify raw access to MPT for snap sync handler why: Logically, `kvt` is not the raw access for the hexary trie (although this holds for the legacy database)
2023-08-04 12:10:09 +01:00
newCoreDbRef LegacyDbMemory,
t.conf.pruneMode == PruneMode.Full,
t.conf.networkId,
t.conf.networkParams
)
2022-12-02 11:39:12 +07:00
t.chainRef = newChain(t.com)
2022-12-02 11:39:12 +07:00
t.com.initializeEmptyDb()
let txPool = TxPoolRef.new(t.com, t.conf.engineSigner)
# txPool must be informed of active head
# so it can know the latest account state
let head = t.com.db.getCanonicalHead()
doAssert txPool.smartHead(head)
var key: JwtSharedKey
let kr = key.fromHex(jwtSecret)
if kr.isErr:
echo "JWT SECRET ERROR: ", kr.error
quit(QuitFailure)
let hooks = if enableAuth:
@[httpJwtAuth(key)]
else:
@[]
t.rpcServer = newRpcHttpServer(["127.0.0.1:" & $t.conf.rpcPort], hooks)
t.sealingEngine = SealingEngineRef.new(
t.chainRef, t.ctx, t.conf.engineSigner,
txPool, EngineStopped
)
2022-12-02 11:39:12 +07:00
let merger = MergerRef.new(t.com.db)
setupEthRpc(t.ethNode, t.ctx, t.com, txPool, t.rpcServer)
setupEngineAPI(t.sealingEngine, t.rpcServer, merger)
2022-12-02 11:39:12 +07:00
setupDebugRpc(t.com, t.rpcServer)
2022-06-17 07:53:33 +07:00
# Do not start clique sealing engine if we are using a Proof of Work chain file
if chainFile.len > 0:
2022-12-02 11:39:12 +07:00
if not importRlpBlock(chainFolder / chainFile, t.com):
2022-06-17 07:53:33 +07:00
quit(QuitFailure)
elif not enableAuth:
2022-06-17 07:53:33 +07:00
t.sealingEngine.start()
t.rpcServer.start()
t.rpcClient = newRpcHttpClient()
waitFor t.rpcClient.connect("127.0.0.1", t.conf.rpcPort, false)
2022-12-02 11:39:12 +07:00
t.gHeader = t.com.genesisHeader
let kRes = PrivateKey.fromHex(vaultKeyHex)
if kRes.isErr:
echo kRes.error
quit(QuitFailure)
t.vaultKey = kRes.get
proc setupELClient*(chainFile: string, enableAuth: bool): TestEnv =
result = TestEnv(
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
)
setupELClient(result, chainFile, enableAuth)
proc setupELClient*(conf: ChainConfig): TestEnv =
result = TestEnv(
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
)
result.conf.networkParams.config = conf
setupELClient(result, "", false)
2023-08-21 09:08:54 +07:00
proc newTestEnv*(): TestEnv =
TestEnv(
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
)
proc newTestEnv*(conf: ChainConfig): TestEnv =
result = TestEnv(
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
)
result.conf.networkParams.config = conf
proc stopELClient*(t: TestEnv) =
waitFor t.rpcClient.close()
waitFor t.sealingEngine.stop()
waitFor t.rpcServer.closeWait()
# TTD is the value specified in the TestSpec + Genesis.Difficulty
proc setRealTTD*(t: TestEnv, ttdValue: int64) =
let realTTD = t.gHeader.difficulty + ttdValue.u256
2022-12-02 11:39:12 +07:00
t.com.setTTD some(realTTD)
t.ttd = realTTD
2023-08-21 09:08:54 +07:00
t.clmock = newCLMocker(t.rpcClient, t.com)
proc slotsToSafe*(t: TestEnv, x: int) =
t.clMock.slotsToSafe = x
proc slotsToFinalized*(t: TestEnv, x: int) =
t.clMock.slotsToFinalized = x
func gwei(n: int64): GasInt {.compileTime.} =
GasInt(n * (10 ^ 9))
2023-08-21 09:08:54 +07:00
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*(t: TestEnv, tc: BaseTx, nonce: AccountNonce): Transaction =
const
gasPrice = 30.gwei
2023-08-21 09:08:54 +07:00
gasTipPrice = 1.gwei
gasFeeCap = gasPrice
gasTipCap = gasTipPrice
let chainId = t.conf.networkParams.config.chainId
2023-08-21 09:08:54 +07:00
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, t.vaultKey, chainId, eip155 = true)
2022-05-29 11:23:03 +07:00
2023-08-21 09:08:54 +07:00
proc makeTx*(t: TestEnv, 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")
t.makeTx(tc.BaseTx, nonce)
proc sendNextTx*(t: TestEnv, tc: BaseTx): bool =
t.tx = t.makeTx(tc, t.nonce)
inc t.nonce
let rr = t.rpcClient.sendTransaction(t.tx)
if rr.isErr:
error "Unable to send transaction", msg=rr.error
return false
return true
proc sendTx*(t: TestEnv, tc: BaseTx, nonce: AccountNonce): bool =
t.tx = t.makeTx(tc, nonce)
let rr = t.rpcClient.sendTransaction(t.tx)
if rr.isErr:
error "Unable to send transaction", msg=rr.error
return false
return true
proc sendTx*(t: TestEnv, tc: BigInitcodeTx, nonce: AccountNonce): bool =
t.tx = t.makeTx(tc, nonce)
let rr = t.rpcClient.sendTransaction(t.tx)
if rr.isErr:
error "Unable to send transaction", msg=rr.error
return false
return true
proc sendTx*(t: TestEnv, tx: Transaction): bool =
t.tx = tx
let rr = t.rpcClient.sendTransaction(t.tx)
if rr.isErr:
error "Unable to send transaction", msg=rr.error
return false
return true
proc verifyPoWProgress*(t: TestEnv, lastBlockHash: ethtypes.Hash256): bool =
2022-05-29 11:23:03 +07:00
let res = waitFor verifyPoWProgress(t.rpcClient, lastBlockHash)
if res.isErr:
error "verify PoW Progress error", msg=res.error
return false
2022-05-29 11:23:03 +07:00
true