nimbus-eth1/nimbus/utils/utils.nim

140 lines
4.4 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.
{.push raises: [].}
import
std/[math, times, strutils],
eth/[rlp, common/eth_types_rlp],
stew/byteutils,
nimcrypto,
results,
../db/aristo,
../constants
export eth_types_rlp
proc calcRootHash[T](items: openArray[T]): Hash256 {.gcsafe.} =
let sig = merkleSignBegin()
for i, t in items:
sig.merkleSignAdd(rlp.encode(i.uint), rlp.encode(t))
sig.merkleSignCommit.value.to(Hash256)
template calcTxRoot*(transactions: openArray[Transaction]): Hash256 =
calcRootHash(transactions)
template calcWithdrawalsRoot*(withdrawals: openArray[Withdrawal]): Hash256 =
calcRootHash(withdrawals)
template calcReceiptsRoot*(receipts: openArray[Receipt]): Hash256 =
calcRootHash(receipts)
func sumHash*(hashes: varargs[Hash256]): Hash256 =
var ctx: sha256
ctx.init()
for hash in hashes:
ctx.update hash.data
ctx.finish result.data
ctx.clear()
proc sumHash*(body: BlockBody): Hash256 {.gcsafe, raises: []} =
let txRoot = calcTxRoot(body.transactions)
let ommersHash = keccakHash(rlp.encode(body.uncles))
let wdRoot = if body.withdrawals.isSome:
calcWithdrawalsRoot(body.withdrawals.get)
else: EMPTY_ROOT_HASH
sumHash(txRoot, ommersHash, wdRoot)
proc sumHash*(header: BlockHeader): Hash256 =
let wdRoot = if header.withdrawalsRoot.isSome:
header.withdrawalsRoot.get
else: EMPTY_ROOT_HASH
sumHash(header.txRoot, header.ommersHash, wdRoot)
func hasBody*(h: BlockHeader): bool =
h.txRoot != EMPTY_ROOT_HASH or
h.ommersHash != EMPTY_UNCLE_HASH or
h.withdrawalsRoot.get(EMPTY_ROOT_HASH) != EMPTY_ROOT_HASH
func generateAddress*(address: EthAddress, nonce: AccountNonce): EthAddress =
result[0..19] = keccakHash(rlp.encodeList(address, nonce)).data.toOpenArray(12, 31)
type ContractSalt* = object
bytes*: array[32, byte]
const ZERO_CONTRACTSALT* = default(ContractSalt)
func generateSafeAddress*(address: EthAddress, salt: ContractSalt,
data: openArray[byte]): EthAddress =
const prefix = [0xff.byte]
let
dataHash = keccakHash(data)
hashResult = withKeccakHash:
h.update(prefix)
h.update(address)
h.update(salt.bytes)
h.update(dataHash.data)
result[0..19] = hashResult.data.toOpenArray(12, 31)
proc crc32*(crc: uint32, buf: openArray[byte]): uint32 =
const kcrc32 = [ 0'u32, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320'u32, 0xf00f9344'u32, 0xd6d6a3e8'u32,
0xcb61b38c'u32, 0x9b64c2b0'u32, 0x86d3d2d4'u32, 0xa00ae278'u32, 0xbdbdf21c'u32]
var crcu32 = not crc
for b in buf:
crcu32 = (crcu32 shr 4) xor kcrc32[int((crcu32 and 0xF) xor (uint32(b) and 0xF'u32))]
crcu32 = (crcu32 shr 4) xor kcrc32[int((crcu32 and 0xF) xor (uint32(b) shr 4'u32))]
result = not crcu32
proc short*(h: Hash256): string =
var bytes: array[6, byte]
bytes[0..2] = h.data[0..2]
bytes[^3..^1] = h.data[^3..^1]
bytes.toHex
func short*(x: Duration): string =
let parts = x.toParts
if parts[Hours] > 0:
result.add $parts[Hours]
result.add ':'
result.add intToStr(parts[Minutes].int, 2)
result.add ':'
result.add intToStr(parts[Seconds].int, 2)
proc decompose*(rlp: var Rlp,
header: var BlockHeader,
body: var BlockBody) {.gcsafe, raises: [RlpError].} =
var blk = rlp.read(EthBlock)
header = system.move(blk.header)
body.transactions = system.move(blk.txs)
body.uncles = system.move(blk.uncles)
body.withdrawals = system.move(blk.withdrawals)
proc decompose*(rlpBytes: openArray[byte],
header: var BlockHeader,
body: var BlockBody) {.gcsafe, raises: [RlpError].} =
var rlp = rlpFromBytes(rlpBytes)
rlp.decompose(header, body)
func gwei*(n: uint64): GasInt =
GasInt(n * (10'u64 ^ 9'u64))
# Helper types to convert gwei into wei more easily
func weiAmount*(w: Withdrawal): UInt256 =
w.amount.u256 * (10'u64 ^ 9'u64).u256
func isGenesis*(header: BlockHeader): bool =
header.number == 0'u64 and
header.parentHash == GENESIS_PARENT_HASH