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
gasPrice*: GasInt
gasLimit*: GasInt
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]
bloom*: BloomFilter
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,205 +9,209 @@ 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":
var rlp = rlpFromBytes seq[byte](@[])
proc suite() =
suite "test api usage":
test "empty bytes are not a proper RLP":
var rlp = rlpFromBytes seq[byte](@[])
check:
not rlp.hasData
not rlp.isBlob
not rlp.isList
not rlp.isEmpty
check:
not rlp.hasData
not rlp.isBlob
not rlp.isList
not rlp.isEmpty
expect Exception:
rlp.skipElem
expect Exception:
rlp.skipElem
expect Exception:
discard rlp.getType
expect Exception:
discard rlp.getType
expect Exception:
for e in rlp:
discard e.getType
expect Exception:
for e in rlp:
discard e.getType
test "you cannot finish a list without appending enough elements":
var writer = initRlpList(3)
writer.append "foo"
writer.append "bar"
test "you cannot finish a list without appending enough elements":
var writer = initRlpList(3)
writer.append "foo"
writer.append "bar"
expect Defect:
discard writer.finish
expect Defect:
discard writer.finish
test "encode/decode object":
type
MyEnum = enum
foo,
bar
test "encode/decode object":
type
MyEnum = enum
foo,
bar
MyObj = object
a: array[3, char]
b: int
c: MyEnum
MyObj = object
a: array[3, char]
b: int
c: MyEnum
var input: MyObj
input.a = ['e', 't', 'h']
input.b = 63
input.c = bar
var input: MyObj
input.a = ['e', 't', 'h']
input.b = 63
input.c = bar
var writer = initRlpWriter()
writer.append(input)
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
var writer = initRlpWriter()
writer.append(input)
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
var output = rlp.read(MyObj)
check:
input == output
var output = rlp.read(MyObj)
check:
input == output
test "encode and decode lists":
var writer = initRlpList(3)
writer.append "foo"
writer.append ["bar", "baz"]
writer.append [30, 40, 50]
test "encode and decode lists":
var writer = initRlpList(3)
writer.append "foo"
writer.append ["bar", "baz"]
writer.append [30, 40, 50]
var
bytes = writer.finish
rlp = rlpFromBytes bytes
var
bytes = writer.finish
rlp = rlpFromBytes bytes
check:
bytes.toHex == "d183666f6fc8836261728362617ac31e2832"
rlp.inspectMatch """
{
"foo"
{
"bar"
"baz"
}
{
byte 30
byte 40
byte 50
}
}
"""
check:
bytes.toHex == "d183666f6fc8836261728362617ac31e2832"
rlp.inspectMatch """
{
"foo"
{
"bar"
"baz"
}
{
byte 30
byte 40
byte 50
}
}
"""
bytes = encodeList(6000,
"Lorem ipsum dolor sit amet",
"Donec ligula tortor, egestas eu est vitae")
bytes = encodeList(6000,
"Lorem ipsum dolor sit amet",
"Donec ligula tortor, egestas eu est vitae")
rlp = rlpFromBytes bytes
check:
rlp.listLen == 3
rlp.listElem(0).toInt(int) == 6000
rlp.listElem(1).toString == "Lorem ipsum dolor sit amet"
rlp.listElem(2).toString == "Donec ligula tortor, egestas eu est vitae"
rlp = rlpFromBytes bytes
check:
rlp.listLen == 3
rlp.listElem(0).toInt(int) == 6000
rlp.listElem(1).toString == "Lorem ipsum dolor sit amet"
rlp.listElem(2).toString == "Donec ligula tortor, egestas eu est vitae"
# test creating RLPs from other RLPs
var list = rlpFromBytes encodeList(rlp.listELem(1), rlp.listELem(0))
# test creating RLPs from other RLPs
var list = rlpFromBytes encodeList(rlp.listELem(1), rlp.listELem(0))
# test that iteration with enterList/skipElem works as expected
doAssert list.enterList # We already know that we are working with a list
check list.toString == "Lorem ipsum dolor sit amet"
list.skipElem
# test that iteration with enterList/skipElem works as expected
doAssert list.enterList # We already know that we are working with a list
check list.toString == "Lorem ipsum dolor sit amet"
list.skipElem
check list.toInt(int32) == 6000.int32
var intVar: int
list >> intVar
check intVar == 6000
check list.toInt(int32) == 6000.int32
var intVar: int
list >> intVar
check intVar == 6000
check(not list.hasData)
expect Exception: list.skipElem
check(not list.hasData)
expect Exception: list.skipElem
test "toBytes":
let rlp = rlpFromHex("f2cb847f000001827666827666a040ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4845ab90b50")
let tok = rlp.listElem(1).toBytes()
check:
tok.len == 32
tok.toHex == "40ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4"
test "toBytes":
let rlp = rlpFromHex("f2cb847f000001827666827666a040ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4845ab90b50")
let tok = rlp.listElem(1).toBytes()
check:
tok.len == 32
tok.toHex == "40ef02798f211da2e8173d37f255be908871ae65060dbb2f77fb29c0421447f4"
test "nested lists":
let listBytes = encode([[1, 2, 3], [5, 6, 7]])
let listRlp = rlpFromBytes listBytes
let sublistRlp0 = listRlp.listElem(0)
let sublistRlp1 = listRlp.listElem(1)
check sublistRlp0.listElem(0).toInt(int) == 1
check sublistRlp0.listElem(1).toInt(int) == 2
check sublistRlp0.listElem(2).toInt(int) == 3
check sublistRlp1.listElem(0).toInt(int) == 5
check sublistRlp1.listElem(1).toInt(int) == 6
check sublistRlp1.listElem(2).toInt(int) == 7
test "nested lists":
let listBytes = encode([[1, 2, 3], [5, 6, 7]])
let listRlp = rlpFromBytes listBytes
let sublistRlp0 = listRlp.listElem(0)
let sublistRlp1 = listRlp.listElem(1)
check sublistRlp0.listElem(0).toInt(int) == 1
check sublistRlp0.listElem(1).toInt(int) == 2
check sublistRlp0.listElem(2).toInt(int) == 3
check sublistRlp1.listElem(0).toInt(int) == 5
check sublistRlp1.listElem(1).toInt(int) == 6
check sublistRlp1.listElem(2).toInt(int) == 7
test "encoding length":
let listBytes = encode([1,2,3,4,5])
let listRlp = rlpFromBytes listBytes
check listRlp.listLen == 5
test "encoding length":
let listBytes = encode([1,2,3,4,5])
let listRlp = rlpFromBytes listBytes
check listRlp.listLen == 5
let emptyListBytes = encode ""
check emptyListBytes.len == 1
let emptyListRlp = rlpFromBytes emptyListBytes
check emptyListRlp.blobLen == 0
let emptyListBytes = encode ""
check emptyListBytes.len == 1
let emptyListRlp = rlpFromBytes emptyListBytes
check emptyListRlp.blobLen == 0
test "basic decoding":
var rlp1 = rlpFromHex("856d6f6f7365")
var rlp2 = rlpFromHex("0x856d6f6f7365")
test "basic decoding":
var rlp1 = rlpFromHex("856d6f6f7365")
var rlp2 = rlpFromHex("0x856d6f6f7365")
check:
rlp1.inspect == q"moose"
rlp2.inspect == q"moose"
check:
rlp1.inspect == q"moose"
rlp2.inspect == q"moose"
test "malformed/truncated RLP":
var rlp = rlpFromHex("b8056d6f6f7365")
expect MalformedRlpError:
discard rlp.inspect
test "malformed/truncated RLP":
var rlp = rlpFromHex("b8056d6f6f7365")
expect MalformedRlpError:
discard rlp.inspect
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]
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]
let rlp = rlpFromBytes(encode((b1, b2, b3)))
check:
rlp.listLen == 3
rlp.listElem(0).toBytes() == b1
rlp.listElem(1).toBytes() == b2
rlp.listElem(2).toBytes() == b3
let rlp = rlpFromBytes(encode((b1, b2, b3)))
check:
rlp.listLen == 3
rlp.listElem(0).toBytes() == b1
rlp.listElem(1).toBytes() == b2
rlp.listElem(2).toBytes() == b3
# The first byte here is the length of the datum (132 - 128 => 4)
$(rlp.listElem(1).rawData) == "[132, 6, 8, 12, 123]"
# 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":
var
rlp = rlpFromBytes rlp.encode("")
b = rlp.toBytes
check $b == "@[]"
test "empty byte arrays":
var
rlp = rlpFromBytes rlp.encode("")
b = rlp.toBytes
check $b == "@[]"
test "encode/decode floats":
for f in [high(float64), low(float64), 0.1, 122.23,
103487315.128934,
1943935743563457201.391754032785692,
0, -0,
Inf, NegInf, NaN]:
test "encode/decode floats":
for f in [high(float64), low(float64), 0.1, 122.23,
103487315.128934,
1943935743563457201.391754032785692,
0, -0,
Inf, NegInf, NaN]:
template isNaN(n): bool =
classify(n) == fcNaN
template isNaN(n): bool =
classify(n) == fcNaN
template chk(input) =
let restored = decode(encode(input), float64)
check restored == input or (input.isNaN and restored.isNaN)
template chk(input) =
let restored = decode(encode(input), float64)
check restored == input or (input.isNaN and restored.isNaN)
chk f
chk -f
chk f
chk -f
test "invalid enum":
type
MyEnum = enum
foo,
bar
test "invalid enum":
type
MyEnum = enum
foo,
bar
var writer = initRlpWriter()
writer.append(2)
writer.append(-1)
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
expect RlpTypeMismatch:
discard rlp.read(MyEnum)
rlp.skipElem()
expect RlpTypeMismatch:
discard rlp.read(MyEnum)
var writer = initRlpWriter()
writer.append(2)
writer.append(-1)
let bytes = writer.finish()
var rlp = rlpFromBytes(bytes)
expect RlpTypeMismatch:
discard rlp.read(MyEnum)
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
test "receipt roundtrip":
var a, b, c, d: Receipt
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
var hash = rlpHash(a)
a.stateRootOrStatus = hashOrStatus(hash)
a.cumulativeGasUsed = 21000
a.logs = @[]
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
b.stateRootOrStatus = hashOrStatus(true)
b.cumulativeGasUsed = 52000
b.logs = @[]
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)
var x = rlp.encode(a)
var y = rlp.encode(b)
let rlpbytes = rlp.encode(blk)
var blk2 = rlp.decode(rlpbytes, EthBlock)
check blk == blk2
check bytes == rlpbytes
c = x.decode(Receipt)
d = y.decode(Receipt)
check c == a
check d == b
proc suite1() =
suite "rlp encoding":
test "receipt roundtrip":
let a = Receipt(
receiptType: LegacyReceiptType,
legacyReceipt: LegacyReceipt(
stateRootOrStatus: hashOrStatus(true),
cumulativeGasUsed: 51000
)
)
check c.hasStateRoot
check c.stateRoot == hash
check d.hasStatus
check d.status == 1
let hash = rlpHash(a)
let b = Receipt(
receiptType: LegacyReceiptType,
legacyReceipt: LegacyReceipt(
stateRootOrStatus: hashOrStatus(hash),
cumulativeGasUsed: 21000
)
)
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
test "access list receipt":
let a = Receipt(
receiptType: AccessListReceiptType,
accessListReceipt: AccessListReceipt(
status: true
)
)
let b = Receipt(
receiptType: AccessListReceiptType,
accessListReceipt: AccessListReceipt(
status: false,
cumulativeGasUsed: 21000
)
)
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,41 +43,45 @@ 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":
var originalBar = Bar(b: "abracadabra",
f: Foo(x: 5'u64, y: "hocus pocus", z: @[100, 200, 300]))
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]))
var bytes = encode(originalBar)
var r = rlpFromBytes(bytes)
var restoredBar = r.read(Bar)
var bytes = encode(originalBar)
var r = rlpFromBytes(bytes)
var restoredBar = r.read(Bar)
check:
originalBar == restoredBar
check:
originalBar == restoredBar
var t1 = Transaction(time: getTime(), amount: 1000, sender: "Alice", receiver: "Bob")
bytes = encode(t1)
var t2 = bytes.decode(Transaction)
var t1 = Transaction(time: getTime(), amount: 1000, sender: "Alice", receiver: "Bob")
bytes = encode(t1)
var t2 = bytes.decode(Transaction)
check:
bytes.toHex == "cd85416c69636583426f628203e8" # verifies that Alice comes first
t2.time == default(Time)
t2.sender == "Alice"
t2.receiver == "Bob"
t2.amount == 1000
check:
bytes.toHex == "cd85416c69636583426f628203e8" # verifies that Alice comes first
t2.time == default(Time)
t2.sender == "Alice"
t2.receiver == "Bob"
t2.amount == 1000
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)
var restored = r.read(CustomSerialized)
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)
var restored = r.read(CustomSerialized)
check:
origVal.customFoo.x == restored.customFoo.x
origVal.customFoo.y.len == restored.customFoo.y.len
restored.ignored == 10
check:
origVal.customFoo.x == restored.customFoo.x
origVal.customFoo.y.len == restored.customFoo.y.len
restored.ignored == 10
test "RLP fields count":
check:
Bar.rlpFieldsCount == 2
Foo.rlpFieldsCount == 3
Transaction.rlpFieldsCount == 3
test "RLP fields count":
check:
Bar.rlpFieldsCount == 2
Foo.rlpFieldsCount == 3
Transaction.rlpFieldsCount == 3
suite()