mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
7d3616e3d9
* Refactor TxPool: leaner and simpler * Rewrite test_txpool Reduce number of tables used, from 5 to 2. Reduce number of files. If need to modify the price rule or other filters, now is far more easier because only one table to work with(sender/nonce). And the other table is just a map from txHash to TxItemRef. Removing transactions from txPool either because of producing new block or syncing became much easier. Removing expired transactions also simple. Explicit Tx Pending, Staged, or Packed status is removed. The status of the transactions can be inferred implicitly. Developer new to TxPool can easily follow the logic. But the most important is we can revive the test_txpool without dirty trick and remove usage of getCanonicalHead furthermore to prepare for better integration with ForkedChain.
753 lines
21 KiB
Nim
753 lines
21 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
# http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed except
|
|
# according to those terms.
|
|
|
|
import
|
|
std/[strformat, strutils, importutils],
|
|
eth/common/[keys, transaction_utils],
|
|
stew/byteutils,
|
|
stew/endians2,
|
|
../nimbus/config,
|
|
../nimbus/db/storage_types,
|
|
../nimbus/common/common,
|
|
../nimbus/core/chain,
|
|
../nimbus/core/tx_pool,
|
|
../nimbus/core/casper,
|
|
../nimbus/transaction,
|
|
../nimbus/constants,
|
|
../nimbus/db/ledger {.all.}, # import all private symbols
|
|
unittest2
|
|
|
|
import results
|
|
|
|
const
|
|
genesisFile = "tests/customgenesis/cancun123.json"
|
|
hexPrivKey = "af1a9be9f1a54421cac82943820a0fe0f601bb5f4f6d0bccc81c613f0ce6ae22"
|
|
|
|
# The above privKey will generate this address
|
|
# senderAddr = hexToByteArray[20]("73cf19657412508833f618a15e8251306b3e6ee5")
|
|
|
|
type
|
|
TestEnv = object
|
|
com: CommonRef
|
|
xdb: CoreDbRef
|
|
txs: seq[Transaction]
|
|
txi: seq[int] # selected index into txs[] (crashable sender addresses)
|
|
vaultKey: PrivateKey
|
|
nonce : uint64
|
|
chainId : ChainId
|
|
xp : TxPoolRef
|
|
chain : ForkedChainRef
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc pp*(a: Address): string =
|
|
a.toHex[32 .. 39].toLowerAscii
|
|
|
|
proc pp*(tx: Transaction): string =
|
|
# "(" & tx.ecRecover.value.pp & "," & $tx.nonce & ")"
|
|
"(" & tx.recoverSender().value().pp & "," & $tx.nonce & ")"
|
|
|
|
proc pp*(h: Hash32): string =
|
|
h.data.toHex[52 .. 63].toLowerAscii
|
|
|
|
proc pp*(tx: Transaction; ledger: LedgerRef): string =
|
|
let address = tx.recoverSender().value()
|
|
"(" & address.pp &
|
|
"," & $tx.nonce &
|
|
";" & $ledger.getNonce(address) &
|
|
"," & $ledger.getBalance(address) &
|
|
")"
|
|
|
|
when isMainModule:
|
|
import chronicles
|
|
|
|
proc setTraceLevel =
|
|
discard
|
|
when defined(chronicles_runtime_filtering) and loggingEnabled:
|
|
setLogLevel(LogLevel.TRACE)
|
|
|
|
proc setErrorLevel =
|
|
discard
|
|
when defined(chronicles_runtime_filtering) and loggingEnabled:
|
|
setLogLevel(LogLevel.ERROR)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private functions
|
|
# ------------------------------------------------------------------------------
|
|
proc privKey(keyHex: string): PrivateKey =
|
|
let kRes = PrivateKey.fromHex(keyHex)
|
|
if kRes.isErr:
|
|
echo kRes.error
|
|
quit(QuitFailure)
|
|
|
|
kRes.get()
|
|
|
|
proc initEnv(): TestEnv =
|
|
let
|
|
conf = makeConfig(@[
|
|
"--custom-network:" & genesisFile
|
|
])
|
|
|
|
let
|
|
com = CommonRef.new(
|
|
newCoreDbRef DefaultDbMemory, nil,
|
|
conf.networkId,
|
|
conf.networkParams
|
|
)
|
|
chain = newForkedChain(com, com.genesisHeader)
|
|
|
|
TestEnv(
|
|
com : com,
|
|
xdb : com.db,
|
|
vaultKey: privKey(hexPrivKey),
|
|
nonce : 0'u64,
|
|
chainId : conf.networkParams.config.chainId,
|
|
xp : TxPoolRef.new(chain),
|
|
chain : chain,
|
|
)
|
|
|
|
func makeTx(
|
|
env: var TestEnv,
|
|
recipient: Address,
|
|
amount: UInt256,
|
|
payload: openArray[byte] = []): Transaction =
|
|
const
|
|
gasLimit = 75000.GasInt
|
|
gasPrice = 30.gwei
|
|
|
|
let tx = Transaction(
|
|
txType : TxLegacy,
|
|
chainId : env.chainId,
|
|
nonce : AccountNonce(env.nonce),
|
|
gasPrice: gasPrice,
|
|
gasLimit: gasLimit,
|
|
to : Opt.some(recipient),
|
|
value : amount,
|
|
payload : @payload
|
|
)
|
|
|
|
inc env.nonce
|
|
signTransaction(tx, env.vaultKey, eip155 = true)
|
|
|
|
func initAddr(z: int): Address =
|
|
const L = sizeof(result)
|
|
result.data[L-sizeof(uint32)..^1] = toBytesBE(z.uint32)
|
|
|
|
proc importBlock(env: TestEnv; blk: Block) =
|
|
env.chain.importBlock(blk).isOkOr:
|
|
raiseAssert "persistBlocks() failed at block #" &
|
|
$blk.header.number & " msg: " & error
|
|
|
|
proc getLedger(com: CommonRef): LedgerRef =
|
|
LedgerRef.init(com.db)
|
|
|
|
func getRecipient(tx: Transaction): Address =
|
|
tx.to.expect("transaction have no recipient")
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Crash test function, finding out about how the transaction framework works ..
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc modBalance(ac: LedgerRef, address: Address) =
|
|
## This function is crucial for profucing the crash. If must
|
|
## modify the balance so that the database gets written.
|
|
# ac.blindBalanceSetter(address)
|
|
ac.addBalance(address, 1.u256)
|
|
|
|
|
|
proc runTrial2ok(env: TestEnv, ledger: LedgerRef; inx: int) =
|
|
## Run two blocks, the first one with *rollback*.
|
|
let eAddr = env.txs[inx].getRecipient
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.rollback(accTx)
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
|
|
ledger.persist()
|
|
|
|
|
|
proc runTrial3(env: TestEnv, ledger: LedgerRef; inx: int; rollback: bool) =
|
|
## Run three blocks, the second one optionally with *rollback*.
|
|
let eAddr = env.txs[inx].getRecipient
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
block body2:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
|
|
if rollback:
|
|
ledger.rollback(accTx)
|
|
break body2
|
|
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
|
|
proc runTrial3Survive(env: TestEnv, ledger: LedgerRef; inx: int; noisy = false) =
|
|
## Run three blocks with extra db frames and *rollback*.
|
|
let eAddr = env.txs[inx].getRecipient
|
|
|
|
block:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.rollback(accTx)
|
|
|
|
dbTx.rollback()
|
|
|
|
block:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
|
|
ledger.persist()
|
|
|
|
ledger.persist()
|
|
|
|
dbTx.commit()
|
|
|
|
|
|
proc runTrial4(env: TestEnv, ledger: LedgerRef; inx: int; rollback: bool) =
|
|
## Like `runTrial3()` but with four blocks and extra db transaction frames.
|
|
let eAddr = env.txs[inx].getRecipient
|
|
|
|
block:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
block body3:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
|
|
if rollback:
|
|
ledger.rollback(accTx)
|
|
break body3
|
|
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
# There must be no dbTx.rollback() here unless `ledger` is
|
|
# discarded and/or re-initialised.
|
|
dbTx.commit()
|
|
|
|
block:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
|
|
block:
|
|
let accTx = ledger.beginSavepoint
|
|
ledger.modBalance(eAddr)
|
|
ledger.commit(accTx)
|
|
ledger.persist()
|
|
|
|
dbTx.commit()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Test Runner
|
|
# ------------------------------------------------------------------------------
|
|
|
|
const
|
|
NumTransactions = 17
|
|
NumBlocks = 13
|
|
feeRecipient = initAddr(401)
|
|
prevRandao = Bytes32 EMPTY_UNCLE_HASH # it can be any valid hash
|
|
|
|
proc runLedgerTransactionTests(noisy = true) =
|
|
suite "Ledger nesting scenarios":
|
|
var env = initEnv()
|
|
|
|
test "Create transactions and blocks":
|
|
var
|
|
recipientSeed = 501
|
|
blockTime = EthTime.now()
|
|
|
|
for _ in 0..<NumBlocks:
|
|
for _ in 0..<NumTransactions:
|
|
let recipient = initAddr(recipientSeed)
|
|
let tx = env.makeTx(recipient, 1.u256)
|
|
check env.xp.addTx(tx).isOk
|
|
inc recipientSeed
|
|
|
|
check env.xp.len == NumTransactions
|
|
env.com.pos.prevRandao = prevRandao
|
|
env.com.pos.feeRecipient = feeRecipient
|
|
env.com.pos.timestamp = blockTime
|
|
|
|
blockTime = EthTime(blockTime.uint64 + 1'u64)
|
|
|
|
let r = env.xp.assembleBlock()
|
|
if r.isErr:
|
|
debugEcho r.error
|
|
check false
|
|
return
|
|
|
|
let blk = r.get.blk
|
|
env.importBlock(blk)
|
|
|
|
check blk.transactions.len == NumTransactions
|
|
env.xp.removeNewBlockTxs(blk)
|
|
for tx in blk.transactions:
|
|
env.txs.add tx
|
|
|
|
let head = env.chain.latestHeader
|
|
test &"Collect unique recipient addresses from {env.txs.len} txs," &
|
|
&" head=#{head.number}":
|
|
# since we generate our own transactions instead of replaying
|
|
# from testnet blocks, the recipients already unique.
|
|
for n,tx in env.txs:
|
|
#let a = tx.getRecipient
|
|
env.txi.add n
|
|
|
|
test &"Run {env.txi.len} two-step trials with rollback":
|
|
for n in env.txi:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
defer: dbTx.dispose()
|
|
let ledger = env.com.getLedger()
|
|
env.runTrial2ok(ledger, n)
|
|
|
|
test &"Run {env.txi.len} three-step trials with rollback":
|
|
for n in env.txi:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
defer: dbTx.dispose()
|
|
let ledger = env.com.getLedger()
|
|
env.runTrial3(ledger, n, rollback = true)
|
|
|
|
test &"Run {env.txi.len} three-step trials with extra db frame rollback" &
|
|
" throwing Exceptions":
|
|
for n in env.txi:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
defer: dbTx.dispose()
|
|
let ledger = env.com.getLedger()
|
|
env.runTrial3Survive(ledger, n, noisy)
|
|
|
|
test &"Run {env.txi.len} tree-step trials without rollback":
|
|
for n in env.txi:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
defer: dbTx.dispose()
|
|
let ledger = env.com.getLedger()
|
|
env.runTrial3(ledger, n, rollback = false)
|
|
|
|
test &"Run {env.txi.len} four-step trials with rollback and db frames":
|
|
for n in env.txi:
|
|
let dbTx = env.xdb.ctx.txFrameBegin()
|
|
defer: dbTx.dispose()
|
|
let ledger = env.com.getLedger()
|
|
env.runTrial4(ledger, n, rollback = true)
|
|
|
|
proc runLedgerBasicOperationsTests() =
|
|
suite "Ledger basic operations tests":
|
|
setup:
|
|
const emptyAcc {.used.} = Account.init()
|
|
|
|
var
|
|
memDB = newCoreDbRef DefaultDbMemory
|
|
ledger {.used.} = LedgerRef.init(memDB)
|
|
address {.used.} = address"0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6"
|
|
code {.used.} = hexToSeqByte("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
|
|
stateRoot {.used.} : Hash32
|
|
|
|
test "accountExists and isDeadAccount":
|
|
check ledger.accountExists(address) == false
|
|
check ledger.isDeadAccount(address) == true
|
|
|
|
ledger.setBalance(address, 1000.u256)
|
|
|
|
check ledger.accountExists(address) == true
|
|
check ledger.isDeadAccount(address) == false
|
|
|
|
ledger.setBalance(address, 0.u256)
|
|
ledger.setNonce(address, 1)
|
|
check ledger.isDeadAccount(address) == false
|
|
|
|
ledger.setCode(address, code)
|
|
ledger.setNonce(address, 0)
|
|
check ledger.isDeadAccount(address) == false
|
|
|
|
ledger.setCode(address, newSeq[byte]())
|
|
check ledger.isDeadAccount(address) == true
|
|
check ledger.accountExists(address) == true
|
|
|
|
test "clone storage":
|
|
# give access to private fields of AccountRef
|
|
privateAccess(AccountRef)
|
|
var x = AccountRef(
|
|
overlayStorage: Table[UInt256, UInt256](),
|
|
originalStorage: newTable[UInt256, UInt256]()
|
|
)
|
|
|
|
x.overlayStorage[10.u256] = 11.u256
|
|
x.overlayStorage[11.u256] = 12.u256
|
|
|
|
x.originalStorage[10.u256] = 11.u256
|
|
x.originalStorage[11.u256] = 12.u256
|
|
|
|
var y = x.clone(cloneStorage = true)
|
|
y.overlayStorage[12.u256] = 13.u256
|
|
y.originalStorage[12.u256] = 13.u256
|
|
|
|
check 12.u256 notin x.overlayStorage
|
|
check 12.u256 in y.overlayStorage
|
|
|
|
check x.overlayStorage.len == 2
|
|
check y.overlayStorage.len == 3
|
|
|
|
check 12.u256 in x.originalStorage
|
|
check 12.u256 in y.originalStorage
|
|
|
|
check x.originalStorage.len == 3
|
|
check y.originalStorage.len == 3
|
|
|
|
test "Ledger various operations":
|
|
var ac = LedgerRef.init(memDB)
|
|
var addr1 = initAddr(1)
|
|
|
|
check ac.isDeadAccount(addr1) == true
|
|
check ac.accountExists(addr1) == false
|
|
check ac.contractCollision(addr1) == false
|
|
|
|
ac.setBalance(addr1, 1000.u256)
|
|
check ac.getBalance(addr1) == 1000.u256
|
|
ac.subBalance(addr1, 100.u256)
|
|
check ac.getBalance(addr1) == 900.u256
|
|
ac.addBalance(addr1, 200.u256)
|
|
check ac.getBalance(addr1) == 1100.u256
|
|
|
|
ac.setNonce(addr1, 1)
|
|
check ac.getNonce(addr1) == 1
|
|
ac.incNonce(addr1)
|
|
check ac.getNonce(addr1) == 2
|
|
|
|
ac.setCode(addr1, code)
|
|
check ac.getCode(addr1) == code
|
|
|
|
ac.setStorage(addr1, 1.u256, 10.u256)
|
|
check ac.getStorage(addr1, 1.u256) == 10.u256
|
|
check ac.getCommittedStorage(addr1, 1.u256) == 0.u256
|
|
|
|
check ac.contractCollision(addr1) == true
|
|
check ac.getCodeSize(addr1) == code.len
|
|
|
|
ac.persist()
|
|
stateRoot = ac.getStateRoot()
|
|
|
|
var db = LedgerRef.init(memDB)
|
|
db.setBalance(addr1, 1100.u256)
|
|
db.setNonce(addr1, 2)
|
|
db.setCode(addr1, code)
|
|
db.setStorage(addr1, 1.u256, 10.u256)
|
|
check stateRoot == db.getStateRoot()
|
|
|
|
# Ledger readonly operations using previous hash
|
|
var ac2 = LedgerRef.init(memDB)
|
|
var addr2 = initAddr(2)
|
|
|
|
check ac2.getCodeHash(addr2) == emptyAcc.codeHash
|
|
check ac2.getBalance(addr2) == emptyAcc.balance
|
|
check ac2.getNonce(addr2) == emptyAcc.nonce
|
|
check ac2.getCode(addr2) == []
|
|
check ac2.getCodeSize(addr2) == 0
|
|
check ac2.getCommittedStorage(addr2, 1.u256) == 0.u256
|
|
check ac2.getStorage(addr2, 1.u256) == 0.u256
|
|
check ac2.contractCollision(addr2) == false
|
|
check ac2.accountExists(addr2) == false
|
|
check ac2.isDeadAccount(addr2) == true
|
|
|
|
ac2.persist()
|
|
# readonly operations should not modify
|
|
# state trie at all
|
|
check ac2.getStateRoot() == stateRoot
|
|
|
|
test "Ledger code retrieval after persist called":
|
|
var ac = LedgerRef.init(memDB)
|
|
var addr2 = initAddr(2)
|
|
ac.setCode(addr2, code)
|
|
ac.persist()
|
|
check ac.getCode(addr2) == code
|
|
let
|
|
key = contractHashKey(keccak256(code))
|
|
val = memDB.ctx.getKvt().get(key.toOpenArray).valueOr: EmptyBlob
|
|
check val == code
|
|
|
|
test "accessList operations":
|
|
proc verifyAddrs(ac: LedgerRef, addrs: varargs[int]): bool =
|
|
for c in addrs:
|
|
if not ac.inAccessList(c.initAddr):
|
|
return false
|
|
true
|
|
|
|
proc verifySlots(ac: LedgerRef, address: int, slots: varargs[int]): bool =
|
|
let a = address.initAddr
|
|
if not ac.inAccessList(a):
|
|
return false
|
|
|
|
for c in slots:
|
|
if not ac.inAccessList(a, c.u256):
|
|
return false
|
|
true
|
|
|
|
proc accessList(ac: LedgerRef, address: int) {.inline.} =
|
|
ac.accessList(address.initAddr)
|
|
|
|
proc accessList(ac: LedgerRef, address, slot: int) {.inline.} =
|
|
ac.accessList(address.initAddr, slot.u256)
|
|
|
|
var ac = LedgerRef.init(memDB)
|
|
|
|
ac.accessList(0xaa)
|
|
ac.accessList(0xbb, 0x01)
|
|
ac.accessList(0xbb, 0x02)
|
|
check ac.verifyAddrs(0xaa, 0xbb)
|
|
check ac.verifySlots(0xbb, 0x01, 0x02)
|
|
check ac.verifySlots(0xaa, 0x01) == false
|
|
check ac.verifySlots(0xaa, 0x02) == false
|
|
|
|
var sp = ac.beginSavepoint
|
|
# some new ones
|
|
ac.accessList(0xbb, 0x03)
|
|
ac.accessList(0xaa, 0x01)
|
|
ac.accessList(0xcc, 0x01)
|
|
ac.accessList(0xcc)
|
|
|
|
check ac.verifyAddrs(0xaa, 0xbb, 0xcc)
|
|
check ac.verifySlots(0xaa, 0x01)
|
|
check ac.verifySlots(0xbb, 0x01, 0x02, 0x03)
|
|
check ac.verifySlots(0xcc, 0x01)
|
|
|
|
ac.rollback(sp)
|
|
check ac.verifyAddrs(0xaa, 0xbb)
|
|
check ac.verifyAddrs(0xcc) == false
|
|
check ac.verifySlots(0xcc, 0x01) == false
|
|
|
|
sp = ac.beginSavepoint
|
|
ac.accessList(0xbb, 0x03)
|
|
ac.accessList(0xaa, 0x01)
|
|
ac.accessList(0xcc, 0x01)
|
|
ac.accessList(0xcc)
|
|
ac.accessList(0xdd, 0x04)
|
|
ac.commit(sp)
|
|
|
|
check ac.verifyAddrs(0xaa, 0xbb, 0xcc)
|
|
check ac.verifySlots(0xaa, 0x01)
|
|
check ac.verifySlots(0xbb, 0x01, 0x02, 0x03)
|
|
check ac.verifySlots(0xcc, 0x01)
|
|
check ac.verifySlots(0xdd, 0x04)
|
|
|
|
test "transient storage operations":
|
|
var ac = LedgerRef.init(memDB)
|
|
|
|
proc tStore(ac: LedgerRef, address, slot, val: int) =
|
|
ac.setTransientStorage(address.initAddr, slot.u256, val.u256)
|
|
|
|
proc tLoad(ac: LedgerRef, address, slot: int): UInt256 =
|
|
ac.getTransientStorage(address.initAddr, slot.u256)
|
|
|
|
proc vts(ac: LedgerRef, address, slot, val: int): bool =
|
|
ac.tLoad(address, slot) == val.u256
|
|
|
|
ac.tStore(0xaa, 3, 66)
|
|
ac.tStore(0xbb, 1, 33)
|
|
ac.tStore(0xbb, 2, 99)
|
|
|
|
check ac.vts(0xaa, 3, 66)
|
|
check ac.vts(0xbb, 1, 33)
|
|
check ac.vts(0xbb, 2, 99)
|
|
check ac.vts(0xaa, 1, 33) == false
|
|
check ac.vts(0xbb, 1, 66) == false
|
|
|
|
var sp = ac.beginSavepoint
|
|
# some new ones
|
|
ac.tStore(0xaa, 3, 77)
|
|
ac.tStore(0xbb, 1, 55)
|
|
ac.tStore(0xcc, 7, 88)
|
|
|
|
check ac.vts(0xaa, 3, 77)
|
|
check ac.vts(0xbb, 1, 55)
|
|
check ac.vts(0xcc, 7, 88)
|
|
|
|
check ac.vts(0xaa, 3, 66) == false
|
|
check ac.vts(0xbb, 1, 33) == false
|
|
check ac.vts(0xbb, 2, 99)
|
|
|
|
ac.rollback(sp)
|
|
check ac.vts(0xaa, 3, 66)
|
|
check ac.vts(0xbb, 1, 33)
|
|
check ac.vts(0xbb, 2, 99)
|
|
check ac.vts(0xcc, 7, 88) == false
|
|
|
|
sp = ac.beginSavepoint
|
|
ac.tStore(0xaa, 3, 44)
|
|
ac.tStore(0xaa, 4, 55)
|
|
ac.tStore(0xbb, 1, 22)
|
|
ac.tStore(0xdd, 2, 66)
|
|
|
|
ac.commit(sp)
|
|
check ac.vts(0xaa, 3, 44)
|
|
check ac.vts(0xaa, 4, 55)
|
|
check ac.vts(0xbb, 1, 22)
|
|
check ac.vts(0xbb, 1, 55) == false
|
|
check ac.vts(0xbb, 2, 99)
|
|
check ac.vts(0xcc, 7, 88) == false
|
|
check ac.vts(0xdd, 2, 66)
|
|
|
|
ac.clearTransientStorage()
|
|
check ac.vts(0xaa, 3, 44) == false
|
|
check ac.vts(0xaa, 4, 55) == false
|
|
check ac.vts(0xbb, 1, 22) == false
|
|
check ac.vts(0xbb, 1, 55) == false
|
|
check ac.vts(0xbb, 2, 99) == false
|
|
check ac.vts(0xcc, 7, 88) == false
|
|
check ac.vts(0xdd, 2, 66) == false
|
|
|
|
test "ledger contractCollision":
|
|
# use previous hash
|
|
var ac = LedgerRef.init(memDB)
|
|
let addr2 = initAddr(2)
|
|
check ac.contractCollision(addr2) == false
|
|
|
|
ac.setStorage(addr2, 1.u256, 1.u256)
|
|
check ac.contractCollision(addr2) == false
|
|
|
|
ac.persist()
|
|
check ac.contractCollision(addr2) == true
|
|
|
|
let addr3 = initAddr(3)
|
|
check ac.contractCollision(addr3) == false
|
|
ac.setCode(addr3, @[0xaa.byte, 0xbb])
|
|
check ac.contractCollision(addr3) == true
|
|
|
|
let addr4 = initAddr(4)
|
|
check ac.contractCollision(addr4) == false
|
|
ac.setNonce(addr4, 1)
|
|
check ac.contractCollision(addr4) == true
|
|
|
|
test "Ledger storage iterator":
|
|
var ac = LedgerRef.init(memDB, storeSlotHash = true)
|
|
let addr2 = initAddr(2)
|
|
ac.setStorage(addr2, 1.u256, 2.u256)
|
|
ac.setStorage(addr2, 2.u256, 3.u256)
|
|
|
|
var keys: seq[UInt256]
|
|
var vals: seq[UInt256]
|
|
for k, v in ac.cachedStorage(addr2):
|
|
keys.add k
|
|
vals.add v
|
|
|
|
# before persist, there are storages in cache
|
|
check keys.len == 2
|
|
check vals.len == 2
|
|
|
|
check 1.u256 in keys
|
|
check 2.u256 in keys
|
|
|
|
# before persist, the values are all original values
|
|
check vals == @[0.u256, 0.u256]
|
|
|
|
keys.reset
|
|
vals.reset
|
|
|
|
for k, v in ac.storage(addr2):
|
|
keys.add k
|
|
vals.add k
|
|
|
|
# before persist, there are no storages in db
|
|
check keys.len == 0
|
|
check vals.len == 0
|
|
|
|
ac.persist()
|
|
for k, v in ac.cachedStorage(addr2):
|
|
keys.add k
|
|
vals.add v
|
|
|
|
# after persist, there are storages in cache
|
|
check keys.len == 2
|
|
check vals.len == 2
|
|
|
|
check 1.u256 in keys
|
|
check 2.u256 in keys
|
|
|
|
# after persist, the values are what we put into
|
|
check 2.u256 in vals
|
|
check 3.u256 in vals
|
|
|
|
keys.reset
|
|
vals.reset
|
|
|
|
for k, v in ac.storage(addr2):
|
|
keys.add k
|
|
vals.add v
|
|
|
|
# after persist, there are storages in db
|
|
check keys.len == 2
|
|
check vals.len == 2
|
|
|
|
check 1.u256 in keys
|
|
check 2.u256 in keys
|
|
|
|
check 2.u256 in vals
|
|
check 3.u256 in vals
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Main function(s)
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc ledgerMain*(noisy = defined(debug)) =
|
|
noisy.runLedgerTransactionTests
|
|
runLedgerBasicOperationsTests()
|
|
|
|
when isMainModule:
|
|
var noisy = defined(debug)
|
|
|
|
setErrorLevel()
|
|
noisy.ledgerMain
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|