Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakout-room discussion #6 (EIP-2718 encoding option) #231

Closed
poojaranjan opened this issue Dec 5, 2020 · 5 comments
Closed

Breakout-room discussion #6 (EIP-2718 encoding option) #231

poojaranjan opened this issue Dec 5, 2020 · 5 comments

Comments

@poojaranjan
Copy link
Contributor

poojaranjan commented Dec 5, 2020

Date and Time

  • Meeting Date/Time: Dec 07, 2020 1500 UTC
  • Meeting Duration: 60 mins

Location

Zoom: Will be shared in the breakout-room in EthR&D discord channel

Agenda

Discussion continued on EIP-2718: Typed Transaction Envelope to have a consensus on the encoding option.

@MicahZoltu
Copy link

MicahZoltu commented Dec 6, 2020

The questions we need to answer:

  1. How do we hash typed transactions?
  2. How do we wire encode (devp2p) typed transactions?
  3. How do we wire encode (devp2p) legacy transactions?

The current 2976 specification changes the way we wire encode legacy transactions. This is incompatible with the "retroactive devp2p protocol change" that @karalabe proposed and we agreed on in the ACD call. I suspect there is a desire to not change the way legacy transactions are encoded for now.

None of the current specifications define how we hash typed transactions. I think many have assumed that we would just do keccak256(TransactionType || TransactionPayload) but that isn't actually defined anywhere. I believe the hash is only used in JSON-RPC and devp2p, which is why it isn't part of 2718. We should probably define this explicitly in 2976.

While questions 1 and 3 have somewhat "obvious" answers that aren't particularly contentious, question 2 has several options that not everyone agrees on and different clients have implemented different things.

Legacy Transaction Format

txList = rlpEncode([
	...,
	rlp_encode([nonce, ...]),
	...,
])
txList = rlpEncode([
	...,
	[nonce, ...],
	...,
])

Opaque bytes

txList = rlp_encode([
	...,
	Bytes.concat([0x01], rlp_encode([chainId, nonce, ...])),
	...,
])

RLP envelope

txList = rlp_encode([
	...,
	[0x01, [chainId, nonce, ...]],
	...,
])

Custom RLP encoding

txList = rlp_encode([
	...,
	[0x01, cahinId, nonce, ...],
	...,
])

RLP heterogeneous sequence

txList = rlp_encode([
	...,
	0x01,
	[chainId, nonce, ...],
	...,
])

@lightclient
Copy link
Member

This is what I believe the corresponding RLP bytes of each of the above approaches should look like. I've omitted the signature field for simplicity.

Opaque Bytes

The decoder will first read the byte string into a buffer. Those bytes will then be decoded into a transaction. IMO, it seems weird to encode wrap legacy transactions in a byte string.

txList = rlp_encode([..., Bytes.concat([0x01], rlp_encode([chainId, nonce, ...])), ...,])
; legacy transaction
b8 XX         ; byte string length
  f8 XX       ; RLP payload length (tx decoder should notice "fX" start and realize the tx is legacy type)
    80        ; account nonce
    0a        ; gas price
    aa        ; gas limit
    bb        ; calldata
    0a        ; amount
    80        ; payload

; typed transaction
b8 XX         ; byte string length
  01          ; transaction type 
  f8 XX       ; RLP payload length (note, this will be arbitrarily defined depending on the tx type)
    01        ; chain id
    80        ; account nonce
    0a        ; gas price
    aa        ; gas limit
    bb        ; calldata
    80        ; amount
    80        ; payload

RLP envelope

The decoder will read the RLP list, starting with the first element. If that first element denotes a typed transaction, the remaining bytes of the inner list will be passed to the transaction decoder. This is essentially the same as above, except that it doesn't wrap legacy txs, but uses an RLP list more as a byte string.

txList = rlp_encode([..., [0x01, [chainId, nonce, ...]], ...])
; legacy transaction
f8 XX 
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; calldata
  0a        ; amount
  80        ; payload

; typed transaction
f8 XX         ; byte string length
  01          ; transaction type 
  f8 XX       ; RLP payload length (note, this will be arbitrarily defined depending on the tx type)
    01        ; chain id
    80        ; account nonce
    0a        ; gas price
    aa        ; gas limit
    bb        ; calldata
    80        ; amount
    80        ; payload

Custom RLP encoding

I'm not sure I've represented this correctly, because as-is it's possible that the transaction type will conflict with the account nonce.

txList = rlp_encode([..., [0x01, cahinId, nonce, ...], ...])
; legacy transaction
f8 XX 
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; calldata  
  0a        ; amount
  80        ; payload

; typed transaction
f8 XX       ; byte string length
  01        ; transaction type 
  01        ; chain id
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; calldata
  80        ; amount
  80        ; payload

RLP heterogeneous sequence

The decoder will read each element in the list. If it encounters a list, it decodes that as a legacy tx. If it encounters an integer, it will pass the remaining bytes to that typed transaction's decoder.

txList = rlp_encode([..., 0x01, [chainId, nonce, ...], ...])
; legacy transaction
f8 XX       ; RLP payload length (tx decoder should notice "fX" start and realize the tx is legacy type)
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; calldata
  0a        ; amount
  80        ; payload

; typed transaction
01          ; transaction type 
f8 XX       ; RLP payload length (note, this will be arbitrarily defined depending on the tx type)
  01        ; chain id
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; calldata
  80        ; amount
  80        ; payload

My thoughts

I believe we'll be best off going with either the Opaque bytes approach or the RLP heterogeneous sequence. At this point, I'm not terribly attached to either. My argument for Opaque bytes is that it keeps a clean interface to interact with a transaction list. If we ever support non-RLP typed txs, it allows a decoder to still determine the number of txs in the list. My argument for RLP heterogeneous sequence is that these are RLP bytes, we shouldn't get too hooked on what they look like or their interface. This format is very amenable to decoding and doesn't wrap things in unnecessary bytes. It's also highly unlikely we'll introduce a non-RLP tx type without a significant overhaul to this system anyways.

@lightclient
Copy link
Member

lightclient commented Dec 7, 2020

Decisions

  1. keccak256(TransactionType || TransactionPayload)
  2. Opaque Bytes
  3. Continue serializing as RLP list of items
  4. Clients MUST NOT propagate typed transaction before the Berlin fork.

Final serialization (signature omitted for simplicity):

; legacy transaction
f8 XX       ; RLP payload length (tx decoder should notice "fX" start and realize the tx is legacy type)
  80        ; account nonce
  0a        ; gas price
  aa        ; gas limit
  bb        ; to
  0a        ; amount
  80        ; calldata

; typed transaction
b8 XX         ; byte string length
  01          ; transaction type 
  f8 XX       ; RLP payload length (note, this will be arbitrarily defined depending on the tx type)
    01        ; chain id
    80        ; account nonce
    0a        ; gas price
    aa        ; gas limit
    bb        ; to
    80        ; amount
    80        ; calldata

@MicahZoltu
Copy link

EIP-2976 has been updated with the decisions made in the meeting.

@poojaranjan
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants