implement eip2718: transaction type envelope

also add more test cases for both tx and receipt
rlp encoding decoding
This commit is contained in:
jangko 2021-05-14 21:48:21 +07:00
parent 8890175b6a
commit 61d5327f55
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
16 changed files with 3606 additions and 261 deletions

View File

@ -8,11 +8,8 @@ export
type
Hash256* = MDigest[256]
EthTime* = Time
VMWord* = UInt256
BlockNonce* = array[8, byte]
AccountNonce* = uint64
Blob* = seq[byte]
@ -33,23 +30,61 @@ type
ForkID* = tuple[crc: uint32, nextFork: uint64]
# EIP 2364/2124
BlockNumber* = UInt256
StorageKey* = array[32, byte]
# beware that although in some cases
# chainId have identical value to networkId
# they are separate entity
ChainId* = distinct uint64
Account* = object
nonce*: AccountNonce
balance*: UInt256
storageRoot*: Hash256
codeHash*: Hash256
Transaction* = object
accountNonce*: AccountNonce
LegacyTx* = object
nonce* : AccountNonce
gasPrice*: GasInt
gasLimit*: GasInt
to* {.rlpCustomSerialization.}: EthAddress
value*: UInt256
payload*: Blob
V*: byte
R*, S*: UInt256
value* : UInt256
payload* : Blob
V* : int64
R*, S* : UInt256
isContractCreation* {.rlpIgnore.}: bool
AccessPair* = object
address* : EthAddress
storageKeys*: seq[StorageKey]
AccessList* = seq[AccessPair]
AccessListTx* = object
chainId* {.rlpCustomSerialization.}: ChainId
nonce* : AccountNonce
gasPrice* : GasInt
gasLimit* : GasInt
to* {.rlpCustomSerialization.}: EthAddress
value* : UInt256
payload* : Blob
accessList*: AccessList
V* : int64
R*, S* : UInt256
isContractCreation* {.rlpIgnore.}: bool
TxType* = enum
LegacyTxType
AccessListTxType
Transaction* = object
case txType*: TxType
of LegacyTxType:
legacyTx*: LegacyTx
of AccessListTxType:
accessListTx*: AccessListTx
TransactionStatus* = enum
Unknown,
Queued,
@ -61,8 +96,6 @@ type
status*: TransactionStatus
data*: Blob
BlockNumber* = UInt256
BlockHeader* = object
parentHash*: Hash256
ommersHash*: Hash256
@ -96,24 +129,33 @@ type
else:
status*: bool
Receipt* = object
LegacyReceipt* = object
stateRootOrStatus*: HashOrStatus
cumulativeGasUsed*: GasInt
bloom*: BloomFilter
logs*: seq[Log]
logs* : seq[Log]
AccessList* = object
# XXX: Specify the structure of this
AccessListReceipt* = object
status*: bool
cumulativeGasUsed*: GasInt
bloom* : BloomFilter
logs* : seq[Log]
ShardTransaction* = object
chain*: uint
shard*: uint
to*: EthAddress
data*: Blob
gas*: GasInt
accessList*: AccessList
code*: Blob
salt*: Hash256
ReceiptType* = enum
LegacyReceiptType
AccessListReceiptType
Receipt* = object
case receiptType*: ReceiptType
of LegacyReceiptType:
legacyReceipt*: LegacyReceipt
of AccessListReceiptType:
accessListReceipt*: AccessListReceipt
EthBlock* = object
header*: BlockHeader
txs* : seq[Transaction]
uncles*: seq[BlockHeader]
CollationHeader* = object
shard*: uint
@ -232,17 +274,17 @@ proc hashOrStatus*(hash: Hash256): HashOrStatus =
proc hashOrStatus*(status: bool): HashOrStatus =
HashOrStatus(isHash: false, status: status)
proc hasStatus*(rec: Receipt): bool {.inline.} =
proc hasStatus*(rec: LegacyReceipt): bool {.inline.} =
rec.stateRootOrStatus.isHash == false
proc hasStateRoot*(rec: Receipt): bool {.inline.} =
proc hasStateRoot*(rec: LegacyReceipt): bool {.inline.} =
rec.stateRootOrStatus.isHash == true
proc stateRoot*(rec: Receipt): Hash256 {.inline.} =
proc stateRoot*(rec: LegacyReceipt): Hash256 {.inline.} =
doAssert(rec.hasStateRoot)
rec.stateRootOrStatus.hash
proc status*(rec: Receipt): int {.inline.} =
proc status*(rec: LegacyReceipt): int {.inline.} =
doAssert(rec.hasStatus)
if rec.stateRootOrStatus.status: 1 else: 0
@ -250,7 +292,7 @@ proc status*(rec: Receipt): int {.inline.} =
# Rlp serialization:
#
proc read*(rlp: var Rlp, T: typedesc[StUint]): T {.inline.} =
proc read*(rlp: var Rlp, T: type StUint): T {.inline.} =
if rlp.isBlob:
let bytes = rlp.toBytes
if bytes.len > 0:
@ -275,7 +317,7 @@ proc append*(rlpWriter: var RlpWriter, value: StUint) =
else:
rlpWriter.append(value.truncate(int))
proc read*(rlp: var Rlp, T: typedesc[Stint]): T {.inline.} =
proc read*(rlp: var Rlp, T: type Stint): T {.inline.} =
# The Ethereum Yellow Paper defines the RLP serialization only
# for unsigned integers:
{.fatal: "RLP serialization of signed integers is not allowed".}
@ -287,20 +329,53 @@ proc append*(rlpWriter: var RlpWriter, value: Stint) =
{.fatal: "RLP serialization of signed integers is not allowed".}
discard
proc read*(rlp: var Rlp, t: var Transaction, _: type EthAddress): EthAddress {.inline.} =
type
TxTypes = LegacyTx | AccessListTx
proc read*(rlp: var Rlp, t: var TxTypes, _: type EthAddress): EthAddress {.inline.} =
if rlp.blobLen != 0:
result = rlp.read(EthAddress)
else:
t.isContractCreation = true
rlp.skipElem()
proc append*(rlpWriter: var RlpWriter, t: Transaction, a: EthAddress) {.inline.} =
proc append*(rlpWriter: var RlpWriter, t: TxTypes, a: EthAddress) {.inline.} =
if t.isContractCreation:
rlpWriter.append("")
else:
rlpWriter.append(a)
proc read*(rlp: var Rlp, T: typedesc[HashOrStatus]): T {.inline.} =
proc read*(rlp: var Rlp, t: var AccessListTx, _: type ChainId): ChainId {.inline.} =
rlp.read(uint64).ChainId
proc append*(rlpWriter: var RlpWriter, t: AccessListTx, a: ChainId) {.inline.} =
rlpWriter.append(a.uint64)
proc append*(rlpWriter: var RlpWriter, tx: Transaction) =
if tx.txType == LegacyTxType:
rlpWriter.append(tx.legacyTx)
else:
var rw = initRlpWriter()
rw.append(1)
rw.append(tx.accessListTx)
rlpWriter.append(rw.finish())
proc read*(rlp: var Rlp, T: type Transaction): T =
if rlp.isList:
result = Transaction(
txType: LegacyTxType,
legacyTx: rlp.read(LegacyTx)
)
else:
let bytes = rlp.read(Blob)
var rr = rlpFromBytes(bytes)
assert(rr.read(int) == 1)
result = Transaction(
txType: AccessListTxType,
accessListTx: rr.read(AccessListTx)
)
proc read*(rlp: var Rlp, T: type HashOrStatus): T {.inline.} =
if rlp.isBlob() and (rlp.blobLen() == 32 or rlp.blobLen() == 1):
if rlp.blobLen == 1:
result = hashOrStatus(rlp.read(uint8) == 1)
@ -334,7 +409,31 @@ proc append*(rlpWriter: var RlpWriter, value: HashOrStatus) {.inline.} =
else:
rlpWriter.append(if value.status: 1'u8 else: 0'u8)
proc read*(rlp: var Rlp, T: typedesc[Time]): T {.inline.} =
proc append*(rlpWriter: var RlpWriter, rec: Receipt) =
if rec.receiptType == LegacyReceiptType:
rlpWriter.append(rec.legacyReceipt)
else:
var rw = initRlpWriter()
rw.append(1)
rw.append(rec.accessListReceipt)
rlpWriter.append(rw.finish())
proc read*(rlp: var Rlp, T: type Receipt): T =
if rlp.isList:
result = Receipt(
receiptType: LegacyReceiptType,
legacyReceipt: rlp.read(LegacyReceipt)
)
else:
let bytes = rlp.read(Blob)
var rr = rlpFromBytes(bytes)
assert(rr.read(int) == 1)
result = Receipt(
receiptType: AccessListReceiptType,
accessListReceipt: rr.read(AccessListReceipt)
)
proc read*(rlp: var Rlp, T: type Time): T {.inline.} =
result = fromUnix(rlp.read(int64))
proc append*(rlpWriter: var RlpWriter, value: HashOrNum) =
@ -344,7 +443,7 @@ proc append*(rlpWriter: var RlpWriter, value: HashOrNum) =
else:
rlpWriter.append(value.number)
proc read*(rlp: var Rlp, T: typedesc[HashOrNum]): T =
proc read*(rlp: var Rlp, T: type HashOrNum): T =
if rlp.blobLen == 32:
result = HashOrNum(isHash: true, hash: rlp.read(Hash256))
else:

View File

@ -2,8 +2,8 @@ import
nimcrypto/keccak,
".."/[common, rlp, keys]
proc initTransaction*(nonce: AccountNonce, gasPrice, gasLimit: GasInt, to: EthAddress,
value: UInt256, payload: Blob, V: byte, R, S: UInt256, isContractCreation = false): Transaction =
proc initLegacyTx*(nonce: AccountNonce, gasPrice, gasLimit: GasInt, to: EthAddress,
value: UInt256, payload: Blob, V: uint64, R, S: UInt256, isContractCreation = false): LegacyTx =
result.accountNonce = nonce
result.gasPrice = gasPrice
result.gasLimit = gasLimit
@ -40,7 +40,7 @@ proc append(rlpWriter: var RlpWriter, t: TransHashObj, a: EthAddress) {.inline.}
const
EIP155_CHAIN_ID_OFFSET* = 35
func rlpEncode*(transaction: Transaction): auto =
func rlpEncode*(transaction: LegacyTx): auto =
# Encode transaction without signature
return rlp.encode(TransHashObj(
accountNonce: transaction.accountNonce,
@ -52,7 +52,7 @@ func rlpEncode*(transaction: Transaction): auto =
mIsContractCreation: transaction.isContractCreation
))
func rlpEncodeEIP155*(tx: Transaction): auto =
func rlpEncodeEIP155*(tx: LegacyTx): auto =
let V = (tx.V.int - EIP155_CHAIN_ID_OFFSET) div 2
# Encode transaction without signature
return rlp.encode(Transaction(
@ -63,11 +63,11 @@ func rlpEncodeEIP155*(tx: Transaction): auto =
value: tx.value,
payload: tx.payload,
isContractCreation: tx.isContractCreation,
V: V.byte,
V: V.uint64,
R: 0.u256,
S: 0.u256
))
func txHashNoSignature*(tx: Transaction): Hash256 =
func txHashNoSignature*(tx: LegacyTx): Hash256 =
# Hash transaction without signature
return keccak256.digest(if tx.V.int >= EIP155_CHAIN_ID_OFFSET: tx.rlpEncodeEIP155 else: tx.rlpEncode)

View File

@ -0,0 +1,42 @@
{
"rlp": "f90263f901f5a0151b04645af991f513d5e11f8ed62e12b73f080af9c7a6a3d98fd6b1503f23faa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0968408b8a2f170bc78230cc2fac3881120a93f7392cf26b609566d8648abfd79a0e8137f2b67ac4680d8103f8b1cd7c05c49f56e4df464b0a79253679f38df9ab4a07f53535270d749f41b9d783aa1abcfceb73cc2a16ecde789cd3bc97a42fbda2ab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018347e7c48262740a80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f868f866800a8301e24194000000000000000000000000000000000000aaaa808086f2ded8deec88a0e7545c5664e63873d7aeb4bb5f92152c3366a9095c9140e5f8453af0998194bea04d24143ac9bc97c0aa07a7074c12ab60484d83d3b447b1e5e6ba5cbf421675bfc0",
"json": {
"header": {
"parentHash": "0x151b04645af991f513d5e11f8ed62e12b73f080af9c7a6a3d98fd6b1503f23fa",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner": "0x0100000000000000000000000000000000000000",
"stateRoot": "0x968408b8a2f170bc78230cc2fac3881120a93f7392cf26b609566d8648abfd79",
"transactionsRoot": "0xe8137f2b67ac4680d8103f8b1cd7c05c49f56e4df464b0a79253679f38df9ab4",
"receiptsRoot": "0x7f53535270d749f41b9d783aa1abcfceb73cc2a16ecde789cd3bc97a42fbda2a",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x20000",
"number": "0x1",
"gasLimit": "0x47e7c4",
"gasUsed": "0x6274",
"timestamp": "0xa",
"extraData": "0x",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"hash": "0x9aa9cdb2afc4ebf893c32b67dedf1dea4291673bf4e80d3227a4e7f8d0feaf68"
},
"transactions": [
{
"type": "0x0",
"chainId": null,
"nonce": "0x0",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": null,
"v": "0xf2ded8deec88",
"r": "0xe7545c5664e63873d7aeb4bb5f92152c3366a9095c9140e5f8453af0998194be",
"s": "0x4d24143ac9bc97c0aa07a7074c12ab60484d83d3b447b1e5e6ba5cbf421675bf",
"hash": "0x7e122173adcc02b9a3c94da426f65c7d46e724e8e3fdb16be73d5e0405e280b6"
}
],
"uncles": null,
"receipts": null
}
}

View File

@ -0,0 +1,65 @@
{
"rlp": "f9032df901f5a09aa9cdb2afc4ebf893c32b67dedf1dea4291673bf4e80d3227a4e7f8d0feaf68a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0fb70f6c0512e7979903607bba8a4f1b18c2dd1060a8eff1b777a2182d05af524a0dfcad019a36acdf0f3fac6b3db02bf1d70012a0bd3eadabea87b856be9a6f1cca0a7a57ba954834e69b55d9115305f14f7faff9beb83443f7bb5526585848c6aefb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000028347e7c482dd201480a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f90131b8c701f8c486796f6c6f7632010a8301e24194000000000000000000000000000000000000aaaa8080f85bf859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000001a0a9efa6b5fd3c2f210c4ec7232058d8dd30c93a456b4f6074429fb09bbd73eb4fa070632eff8bf0933381917c9161a98494e34fc7b836ee150445cae9ab151d267bf866020a8301e24194000000000000000000000000000000000000aaaa808086f2ded8deec88a055a39da3ce02c75e976ad84f608771080811a5ef322c6b6536c362f716c60985a018ab5df4198436eacd0e991f59bdeb8da9a75c678067db6b1a4d07881555c7a8c0",
"json": {
"header": {
"parentHash": "0x9aa9cdb2afc4ebf893c32b67dedf1dea4291673bf4e80d3227a4e7f8d0feaf68",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner": "0x0100000000000000000000000000000000000000",
"stateRoot": "0xfb70f6c0512e7979903607bba8a4f1b18c2dd1060a8eff1b777a2182d05af524",
"transactionsRoot": "0xdfcad019a36acdf0f3fac6b3db02bf1d70012a0bd3eadabea87b856be9a6f1cc",
"receiptsRoot": "0xa7a57ba954834e69b55d9115305f14f7faff9beb83443f7bb5526585848c6aef",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x20000",
"number": "0x2",
"gasLimit": "0x47e7c4",
"gasUsed": "0xdd20",
"timestamp": "0x14",
"extraData": "0x",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"hash": "0xe1807e7366284bc72d34c8f02318f81c6598454dbff4c6cdd71e872cd8d5748c"
},
"transactions": [
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x1",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x1",
"r": "0xa9efa6b5fd3c2f210c4ec7232058d8dd30c93a456b4f6074429fb09bbd73eb4f",
"s": "0x70632eff8bf0933381917c9161a98494e34fc7b836ee150445cae9ab151d267b",
"hash": "0x1916413ac8d1d5ee4eda786e5fe29509a109910f800894e0e18eb84abb7564cb"
},
{
"type": "0x0",
"chainId": null,
"nonce": "0x2",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": null,
"v": "0xf2ded8deec88",
"r": "0x55a39da3ce02c75e976ad84f608771080811a5ef322c6b6536c362f716c60985",
"s": "0x18ab5df4198436eacd0e991f59bdeb8da9a75c678067db6b1a4d07881555c7a8",
"hash": "0x54c6cfb51cbbe2c562e17a0d6ee1324f1b50013a9b9d47589cedcf0ec4ac342a"
}
],
"uncles": null,
"receipts": null
}
}

View File

@ -0,0 +1,102 @@
{
"rlp": "f904b1f901f6a0e1807e7366284bc72d34c8f02318f81c6598454dbff4c6cdd71e872cd8d5748ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a025e5b4b7668760c0aa01d44c061d77e24b53f6d247d3e1d85a91e23646c1d679a0be53a36dd90786b4cd30fb0f3677ad3ce5f804a5615872a7b0512b6be82639a2a076946d9f034a6657c6832a6ad4df3ef0ddf3fa9f3f8be98ea64880fb23bd23e3b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000038347e7c48301883c1e80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f902b4b9012301f9011f86796f6c6f7632030a8301e24194000000000000000000000000000000000000aaaa8080f8b6f859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f859940100000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0010000000000000000000000000000000000000000000000000000000000000001a0635c44b8110989ef84c77de11a377f19cbd84660559ed76b37ba0f7fdee1fb40a012e1576d168301614720c68f1a9e9d5ed20e23622dab6c3587b11177155d59f4b9012301f9011f86796f6c6f7632040a8301e24194000000000000000000000000000000000000aaaa8080f8b6f859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f859940100000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0010000000000000000000000000000000000000000000000000000000000000001a00380e446bf3992ee1df44b8177a11e948dc52cc3faa8eae059a52b7183126c0fa05206f0f35648d3b8f23092d4d7bdccb926967d840a269cf65b706a8a359b9029f866050a8301e24194000000000000000000000000000000000000aaaa808086f2ded8deec87a0ea5de382dbf422aa1bd156547a2bc3a9357d745a68cdc9203b14812307068567a0388f7425b873ae204d43d91f4997ca41d2af6759be49538b174a06f67d5741b5c0",
"json": {
"header": {
"parentHash": "0xe1807e7366284bc72d34c8f02318f81c6598454dbff4c6cdd71e872cd8d5748c",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner": "0x0100000000000000000000000000000000000000",
"stateRoot": "0x25e5b4b7668760c0aa01d44c061d77e24b53f6d247d3e1d85a91e23646c1d679",
"transactionsRoot": "0xbe53a36dd90786b4cd30fb0f3677ad3ce5f804a5615872a7b0512b6be82639a2",
"receiptsRoot": "0x76946d9f034a6657c6832a6ad4df3ef0ddf3fa9f3f8be98ea64880fb23bd23e3",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x20000",
"number": "0x3",
"gasLimit": "0x47e7c4",
"gasUsed": "0x1883c",
"timestamp": "0x1e",
"extraData": "0x",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"hash": "0x1615129d2aa7b437cd40e3aa1a5794af9e40b07b9b017014e4123cefeef785ce"
},
"transactions": [
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x3",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0100000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0100000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x1",
"r": "0x635c44b8110989ef84c77de11a377f19cbd84660559ed76b37ba0f7fdee1fb40",
"s": "0x12e1576d168301614720c68f1a9e9d5ed20e23622dab6c3587b11177155d59f4",
"hash": "0x54471f503901f2c2fe392e43df0377a11f9a1cd9cde0ec5c68c89eac1723e02a"
},
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x4",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0100000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0100000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x1",
"r": "0x380e446bf3992ee1df44b8177a11e948dc52cc3faa8eae059a52b7183126c0f",
"s": "0x5206f0f35648d3b8f23092d4d7bdccb926967d840a269cf65b706a8a359b9029",
"hash": "0xe3a1354e84d22ebbca0c55751937b075083f0f0e3a47c65fc7249d86f872f268"
},
{
"type": "0x0",
"chainId": null,
"nonce": "0x5",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": null,
"v": "0xf2ded8deec87",
"r": "0xea5de382dbf422aa1bd156547a2bc3a9357d745a68cdc9203b14812307068567",
"s": "0x388f7425b873ae204d43d91f4997ca41d2af6759be49538b174a06f67d5741b5",
"hash": "0x44b1e9999ac02a3b0daf1391be16bb00a262079706418697094bab5f37b522d7"
}
],
"uncles": null,
"receipts": null
}
}

View File

@ -0,0 +1,153 @@
{
"rlp": "f906ebf901f6a01615129d2aa7b437cd40e3aa1a5794af9e40b07b9b017014e4123cefeef785cea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0e2c895d53740e942c84623e1612189e72eea9e767b150cc0d8802b490f2574b2a060b6fa13cd50ea3732f59eb726368639dea2006ab4b67dc5730ea27b0cd75732a058ac726e0fc55cd550539c38baf3f6023615e2657ceedccc21ce7edd6516bc31b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000048347e7c4830263c82880a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f904eeb9017f01f9017b86796f6c6f7632060a8301e24194000000000000000000000000000000000000aaaa8080f90111f859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f859940100000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00100000000000000000000000000000000000000000000000000000000000000f859940200000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0020000000000000000000000000000000000000000000000000000000000000001a0587b3fd59a84469be7c918ae73047141027d27c47cc63f3cf13c6161bf92efaaa0453d3cd2dffd1f048a58fb1046917327f5e95cc8aedc47f82d41bffebfe31bbdb9017f01f9017b86796f6c6f7632070a8301e24194000000000000000000000000000000000000aaaa8080f90111f859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f859940100000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00100000000000000000000000000000000000000000000000000000000000000f859940200000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0020000000000000000000000000000000000000000000000000000000000000080a0b1944f4797bf4da4d041a66be9c41c317b40d158894103ccd50de5e4ca174b4aa079d6834c013b40d0039ca6755cecc72938461e5b8cd8d3619ddcdfb15c15b866b9017f01f9017b86796f6c6f7632080a8301e24194000000000000000000000000000000000000aaaa8080f90111f859940000000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000f859940100000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a00100000000000000000000000000000000000000000000000000000000000000f859940200000000000000000000000000000000000000f842a00000000000000000000000000000000000000000000000000000000000000000a0020000000000000000000000000000000000000000000000000000000000000001a0793cd38309611e0117269275243fc3761fe233dc371918e450b547c70132c033a07276d4b20788938ca0ff7e4e921aec7739103dc73d3b953f47947ef194720757f866090a8301e24194000000000000000000000000000000000000aaaa808086f2ded8deec88a0a6528544064aef10d166e16d3968ae83aa29161beb57f2756dfd1151682adbe7a0507fe2d475ffab209e718345a3ad9fb20fee6e15a8c4980df3ed8ff0a714367ac0",
"json": {
"header": {
"parentHash": "0x1615129d2aa7b437cd40e3aa1a5794af9e40b07b9b017014e4123cefeef785ce",
"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"miner": "0x0100000000000000000000000000000000000000",
"stateRoot": "0xe2c895d53740e942c84623e1612189e72eea9e767b150cc0d8802b490f2574b2",
"transactionsRoot": "0x60b6fa13cd50ea3732f59eb726368639dea2006ab4b67dc5730ea27b0cd75732",
"receiptsRoot": "0x58ac726e0fc55cd550539c38baf3f6023615e2657ceedccc21ce7edd6516bc31",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x20000",
"number": "0x4",
"gasLimit": "0x47e7c4",
"gasUsed": "0x263c8",
"timestamp": "0x28",
"extraData": "0x",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000000",
"hash": "0xc6340ac0a1b76cae78479a4bc6211031550719fa9b58ae42d773dce7ff7409ce"
},
"transactions": [
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x6",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0100000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0100000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0200000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0200000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x1",
"r": "0x587b3fd59a84469be7c918ae73047141027d27c47cc63f3cf13c6161bf92efaa",
"s": "0x453d3cd2dffd1f048a58fb1046917327f5e95cc8aedc47f82d41bffebfe31bbd",
"hash": "0xbc9b06b5d31e6e257a3c25048e935ba433c68fdd5fa5d0ddd726d5ab7356aafd"
},
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x7",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0100000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0100000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0200000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0200000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x0",
"r": "0xb1944f4797bf4da4d041a66be9c41c317b40d158894103ccd50de5e4ca174b4a",
"s": "0x79d6834c013b40d0039ca6755cecc72938461e5b8cd8d3619ddcdfb15c15b866",
"hash": "0x474ec2766068f9e9d0548aca3769ca406fdde21ba87c254d9230c18be35fe99a"
},
{
"type": "0x1",
"chainId": "0x796f6c6f7632",
"nonce": "0x8",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": [
{
"address": "0x0000000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0100000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0100000000000000000000000000000000000000000000000000000000000000"
]
},
{
"address": "0x0200000000000000000000000000000000000000",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0200000000000000000000000000000000000000000000000000000000000000"
]
}
],
"v": "0x1",
"r": "0x793cd38309611e0117269275243fc3761fe233dc371918e450b547c70132c033",
"s": "0x7276d4b20788938ca0ff7e4e921aec7739103dc73d3b953f47947ef194720757",
"hash": "0xe46963eb63cd75a120990ca597532020bc2dcefc4588025c0d50901681a7aae9"
},
{
"type": "0x0",
"chainId": null,
"nonce": "0x9",
"gasPrice": "0xa",
"gas": "0x1e241",
"to": "0x000000000000000000000000000000000000aaaa",
"value": "0x0",
"input": "0x",
"accessList": null,
"v": "0xf2ded8deec88",
"r": "0xa6528544064aef10d166e16d3968ae83aa29161beb57f2756dfd1151682adbe7",
"s": "0x507fe2d475ffab209e718345a3ad9fb20fee6e15a8c4980df3ed8ff0a714367a",
"hash": "0x61fc16fea6b57d81f269e733cdd15d994bbc10dc6e9b0acbedbe32e6fe70a06c"
}
],
"uncles": null,
"receipts": null
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,39 @@
{
"config": {
"chainId": 133519467574834,
"homesteadBlock": 0,
"daoForkSupport": true,
"eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"yoloV2Block": 0,
"clique": {
"period": 15,
"epoch": 30000
}
},
"nonce": "0x0",
"timestamp": "0x0",
"extraData": "0x",
"gasLimit": "0x0",
"difficulty": null,
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"000000000000000000000000000000000000aaaa": {
"code": "0x58585454",
"balance": "0x0"
},
"71562b71999873db5b286df957af199ec94617f7": {
"balance": "0x3b9aca00"
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}

View File

@ -9,7 +9,9 @@ proc q(s: string): string = "\"" & s & "\""
proc i(s: string): string = s.replace(" ").replace("\n")
proc inspectMatch(r: Rlp, s: string): bool = r.inspect.i == s.i
test "empty bytes are not a proper RLP":
proc suite() =
suite "test api usage":
test "empty bytes are not a proper RLP":
var rlp = rlpFromBytes seq[byte](@[])
check:
@ -28,7 +30,7 @@ test "empty bytes are not a proper RLP":
for e in rlp:
discard e.getType
test "you cannot finish a list without appending enough elements":
test "you cannot finish a list without appending enough elements":
var writer = initRlpList(3)
writer.append "foo"
writer.append "bar"
@ -36,7 +38,7 @@ test "you cannot finish a list without appending enough elements":
expect Defect:
discard writer.finish
test "encode/decode object":
test "encode/decode object":
type
MyEnum = enum
foo,
@ -61,7 +63,7 @@ test "encode/decode object":
check:
input == output
test "encode and decode lists":
test "encode and decode lists":
var writer = initRlpList(3)
writer.append "foo"
writer.append ["bar", "baz"]
@ -115,14 +117,14 @@ test "encode and decode lists":
check(not list.hasData)
expect Exception: list.skipElem
test "toBytes":
test "toBytes":
let rlp = rlpFromHex("f2cb847f000001827666827666a040ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4845ab90b50")
let tok = rlp.listElem(1).toBytes()
check:
tok.len == 32
tok.toHex == "40ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4"
test "nested lists":
test "nested lists":
let listBytes = encode([[1, 2, 3], [5, 6, 7]])
let listRlp = rlpFromBytes listBytes
let sublistRlp0 = listRlp.listElem(0)
@ -134,7 +136,7 @@ test "nested lists":
check sublistRlp1.listElem(1).toInt(int) == 6
check sublistRlp1.listElem(2).toInt(int) == 7
test "encoding length":
test "encoding length":
let listBytes = encode([1,2,3,4,5])
let listRlp = rlpFromBytes listBytes
check listRlp.listLen == 5
@ -144,7 +146,7 @@ test "encoding length":
let emptyListRlp = rlpFromBytes emptyListBytes
check emptyListRlp.blobLen == 0
test "basic decoding":
test "basic decoding":
var rlp1 = rlpFromHex("856d6f6f7365")
var rlp2 = rlpFromHex("0x856d6f6f7365")
@ -152,12 +154,12 @@ test "basic decoding":
rlp1.inspect == q"moose"
rlp2.inspect == q"moose"
test "malformed/truncated RLP":
test "malformed/truncated RLP":
var rlp = rlpFromHex("b8056d6f6f7365")
expect MalformedRlpError:
discard rlp.inspect
test "encode byte arrays":
test "encode byte arrays":
var b1 = [byte(1), 2, 5, 7, 8]
var b2 = [byte(6), 8, 12, 123]
var b3 = @[byte(122), 56, 65, 12]
@ -172,13 +174,13 @@ test "encode byte arrays":
# The first byte here is the length of the datum (132 - 128 => 4)
$(rlp.listElem(1).rawData) == "[132, 6, 8, 12, 123]"
test "empty byte arrays":
test "empty byte arrays":
var
rlp = rlpFromBytes rlp.encode("")
b = rlp.toBytes
check $b == "@[]"
test "encode/decode floats":
test "encode/decode floats":
for f in [high(float64), low(float64), 0.1, 122.23,
103487315.128934,
1943935743563457201.391754032785692,
@ -195,7 +197,7 @@ test "encode/decode floats":
chk f
chk -f
test "invalid enum":
test "invalid enum":
type
MyEnum = enum
foo,
@ -211,3 +213,5 @@ test "invalid enum":
rlp.skipElem()
expect RlpTypeMismatch:
discard rlp.read(MyEnum)
suite()

View File

@ -1,7 +1,8 @@
{.used.}
import
std/unittest,
std/[unittest, os, json],
stew/byteutils,
../../eth/[common, rlp]
proc `==`(a, b: HashOrStatus): bool =
@ -12,29 +13,92 @@ proc `==`(a, b: HashOrStatus): bool =
else:
result = result and a.status == b.status
suite "rlp encoding":
func `==`(a, b: ChainId): bool =
a.uint64 == b.uint64
func `==`(a, b: Transaction): bool =
if a.txType != b.txType:
return false
if a.txType == LegacyTxType:
return a.legacyTx == b.legacyTx
else:
return a.accessListTx == b.accessListTx
func `==`(a, b: Receipt): bool =
if a.receiptType != b.receiptType:
return false
if a.receiptType == LegacyReceiptType:
return a.legacyReceipt == b.legacyReceipt
else:
return a.accessListReceipt == b.accessListReceipt
proc loadFile(x: int) =
let fileName = "tests" / "rlp" / "eip2718" / "acl_block_" & $x & ".json"
test fileName:
let n = json.parseFile(fileName)
let data = n["rlp"].getStr()
var bytes = hexToSeqByte(data)
var blk = rlp.decode(bytes, EthBlock)
let rlpbytes = rlp.encode(blk)
var blk2 = rlp.decode(rlpbytes, EthBlock)
check blk == blk2
check bytes == rlpbytes
proc suite1() =
suite "rlp encoding":
test "receipt roundtrip":
var a, b, c, d: Receipt
let a = Receipt(
receiptType: LegacyReceiptType,
legacyReceipt: LegacyReceipt(
stateRootOrStatus: hashOrStatus(true),
cumulativeGasUsed: 51000
)
)
var hash = rlpHash(a)
a.stateRootOrStatus = hashOrStatus(hash)
a.cumulativeGasUsed = 21000
a.logs = @[]
let hash = rlpHash(a)
let b = Receipt(
receiptType: LegacyReceiptType,
legacyReceipt: LegacyReceipt(
stateRootOrStatus: hashOrStatus(hash),
cumulativeGasUsed: 21000
)
)
b.stateRootOrStatus = hashOrStatus(true)
b.cumulativeGasUsed = 52000
b.logs = @[]
let abytes = rlp.encode(a)
let bbytes = rlp.encode(b)
let aa = rlp.decode(abytes, Receipt)
let bb = rlp.decode(bbytes, Receipt)
check aa == a
check bb == b
var x = rlp.encode(a)
var y = rlp.encode(b)
test "access list receipt":
let a = Receipt(
receiptType: AccessListReceiptType,
accessListReceipt: AccessListReceipt(
status: true
)
)
c = x.decode(Receipt)
d = y.decode(Receipt)
check c == a
check d == b
let b = Receipt(
receiptType: AccessListReceiptType,
accessListReceipt: AccessListReceipt(
status: false,
cumulativeGasUsed: 21000
)
)
check c.hasStateRoot
check c.stateRoot == hash
check d.hasStatus
check d.status == 1
let abytes = rlp.encode(a)
let bbytes = rlp.encode(b)
let aa = rlp.decode(abytes, Receipt)
let bb = rlp.decode(bbytes, Receipt)
check aa == a
check bb == b
proc suite2() =
suite "eip 2718 transaction":
for i in 0..<10:
loadFile(i)
suite1()
suite2()

View File

@ -43,7 +43,9 @@ proc read*(rlp: var Rlp, holder: var CustomSerialized, T: type Foo): Foo =
result.y = newString(rlp.read(int))
holder.ignored = rlp.read(int) * 2
test "encoding and decoding an object":
proc suite() =
suite "object serialization":
test "encoding and decoding an object":
var originalBar = Bar(b: "abracadabra",
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
@ -65,7 +67,7 @@ test "encoding and decoding an object":
t2.receiver == "Bob"
t2.amount == 1000
test "custom field serialization":
test "custom field serialization":
var origVal = CustomSerialized(customFoo: Foo(x: 10'u64, y: "y", z: @[]), ignored: 5)
var bytes = encode(origVal)
var r = rlpFromBytes(bytes)
@ -76,8 +78,10 @@ test "custom field serialization":
origVal.customFoo.y.len == restored.customFoo.y.len
restored.ignored == 10
test "RLP fields count":
test "RLP fields count":
check:
Bar.rlpFieldsCount == 2
Foo.rlpFieldsCount == 3
Transaction.rlpFieldsCount == 3
suite()