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

support Arbitrum legacy transactions and receipts #114

Merged
merged 26 commits into from
Jul 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c9224c4
arb-legacy transaction update
tsahee May 26, 2022
7c0e2ab
add genesisBlockNumber to arb chain params
tsahee May 31, 2022
212c8b1
move ClipToPostNitroGenesis to blockchain & use params
rachel-bousfield Jun 1, 2022
d7770e3
Merge commit '7c0e2ab4ccc68ebd4d29ec23dd1964b171d94c22' into rely-on-…
rachel-bousfield Jun 1, 2022
7590a32
ClipToPostNitro API fix
tsahee Jun 1, 2022
2f4ff02
expand arbitrum legacy Tx type
tsahee Jun 1, 2022
2e8dfcd
remove cruft
tsahee Jun 1, 2022
d9de7d7
arbitrumSigner support for arblegacyTx
tsahee Jun 9, 2022
65bd96f
support rinkeby devtest chain
tsahee Jun 12, 2022
bdf71b3
arbitrum legacy is not London
tsahee Jun 13, 2022
9c0f658
arblegacy type receipt
tsahee Jun 16, 2022
e290afa
Merge remote-tracking branch 'origin/master' into HEAD
tsahee Jun 16, 2022
0dccfa2
contractaddress for failed arblegacy receipt
tsahee Jun 16, 2022
f33e401
arbLegacyReceipt: store contractaddress
tsahee Jun 16, 2022
ea8850d
json enc/dec for ArbLegacyTx
tsahee Jun 16, 2022
c347db0
Merge remote-tracking branch 'origin/master' into arbitrum_legacy
tsahee Jun 28, 2022
038d4d9
Merge remote-tracking branch 'origin/master' into arbitrum_legacy
tsahee Jun 28, 2022
9276314
only add block fields for nitro
tsahee Jul 6, 2022
ddb137f
Merge branch 'master' into arbitrum_legacy
PlasmaPower Jul 13, 2022
43f50e2
Don't attempt to commit empty state roots
PlasmaPower Jul 13, 2022
eb90573
Merge remote-tracking branch 'origin/master' into arbitrum_legacy
tsahee Jul 19, 2022
064bca8
Merge remote-tracking branch 'origin/arbitrum_legacy' into arbitrum_l…
tsahee Jul 19, 2022
a7efb43
Return status in RPC instead of a 1-byte root for legacy receipts
PlasmaPower Jul 21, 2022
8ec3b10
Merge pull request #131 from OffchainLabs/legacy-receipt-status
tsahee Jul 22, 2022
ba0218b
fix rinkeby testnet params
tsahee Jul 23, 2022
2140a84
fix rinkeby conf
tsahee Jul 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,9 @@ func (bc *BlockChain) Stop() {
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
if number := bc.CurrentBlock().NumberU64(); number > offset {
recent := bc.GetBlockByNumber(number - offset)
if recent.Root() == (common.Hash{}) {
continue
}

log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
if err := triedb.Commit(recent.Root(), true, nil); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion core/types/arb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ func (info HeaderInfo) UpdateHeaderWithInfo(header *Header) {
}

func DeserializeHeaderExtraInformation(header *Header) (HeaderInfo, error) {
if header.Number.Sign() == 0 || len(header.Extra) == 0 {
if header.BaseFee == nil || header.BaseFee.Sign() == 0 || len(header.Extra) == 0 {
// imported blocks have no base fee
// The genesis block doesn't have an ArbOS encoded extra field
return HeaderInfo{}, nil
}
Expand Down
134 changes: 27 additions & 107 deletions core/types/arbitrum_legacy_tx.go
Original file line number Diff line number Diff line change
@@ -1,126 +1,46 @@
package types

import (
"math/big"
"bytes"
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rlp"
)

// Data as received from Arb1 chain
type ArbitrumLegacyTransactionResult struct {
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`

// Arbitrum Specific Fields
L1SeqNum *hexutil.Big `json:"l1SequenceNumber"`
ParentRequestId *common.Hash `json:"parentRequestId"`
IndexInParent *hexutil.Big `json:"indexInParent"`
ArbType hexutil.Uint64 `json:"arbType"`
ArbSubType *hexutil.Uint64 `json:"arbSubType"`
L1BlockNumber *hexutil.Big `json:"l1BlockNumber"`
}

type ArbitrumLegacyTxData struct {
Gas uint64
GasPrice *big.Int
Hash common.Hash // Hash cannot be locally computed from other fields
Data []byte
Nonce uint64
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int
V, R, S *big.Int
LegacyTx
HashOverride common.Hash // Hash cannot be locally computed from other fields
EffectiveGasPrice uint64
L1BlockNumber uint64
}

func (tx *ArbitrumLegacyTxData) copy() TxData {
cpy := &ArbitrumLegacyTxData{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
Hash: tx.Hash,
// These are initialized below.
Value: new(big.Int),
GasPrice: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.GasPrice != nil {
cpy.GasPrice.Set(tx.GasPrice)
func NewArbitrumLegacyTx(origTx *Transaction, hashOverride common.Hash, effectiveGas uint64, l1Block uint64) (*Transaction, error) {
if origTx.Type() != LegacyTxType {
return nil, errors.New("attempt to arbitrum-wrap non-legacy transaction")
}
if tx.V != nil {
cpy.V.Set(tx.V)
legacyPtr := origTx.GetInner().(*LegacyTx)
inner := ArbitrumLegacyTxData{
LegacyTx: *legacyPtr,
HashOverride: hashOverride,
EffectiveGasPrice: effectiveGas,
L1BlockNumber: l1Block,
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
return NewTx(&inner), nil
}

func ArbitrumLegacyFromTransactionResult(result ArbitrumLegacyTransactionResult) *Transaction {
gas := uint64(result.Gas)
nonce := uint64(result.Nonce)
gasPrice := (*big.Int)(result.GasPrice)
value := (*big.Int)(result.Value)
v := (*big.Int)(result.V)
r := (*big.Int)(result.R)
s := (*big.Int)(result.S)
hash := common.Hash(result.Hash)
to := copyAddressPtr(result.To)
var data []byte = result.Input
arblegacy := ArbitrumLegacyTxData{
Gas: gas,
GasPrice: gasPrice,
Hash: hash,
Data: data,
Nonce: nonce,
To: to,
Value: value,
V: v,
R: r,
S: s,
func (tx *ArbitrumLegacyTxData) copy() TxData {
legacyCopy := tx.LegacyTx.copy().(*LegacyTx)
return &ArbitrumLegacyTxData{
LegacyTx: *legacyCopy,
HashOverride: tx.HashOverride,
EffectiveGasPrice: tx.EffectiveGasPrice,
L1BlockNumber: tx.L1BlockNumber,
}
return NewTx(&arblegacy)
}

// accessors for innerTx.
func (tx *ArbitrumLegacyTxData) txType() byte { return ArbitrumLegacyTxType }
func (tx *ArbitrumLegacyTxData) chainID() *big.Int { return deriveChainId(tx.V) }
func (tx *ArbitrumLegacyTxData) accessList() AccessList { return nil }
func (tx *ArbitrumLegacyTxData) data() []byte { return tx.Data }
func (tx *ArbitrumLegacyTxData) gas() uint64 { return tx.Gas }
func (tx *ArbitrumLegacyTxData) gasPrice() *big.Int { return tx.GasPrice }
func (tx *ArbitrumLegacyTxData) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *ArbitrumLegacyTxData) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *ArbitrumLegacyTxData) value() *big.Int { return tx.Value }
func (tx *ArbitrumLegacyTxData) nonce() uint64 { return tx.Nonce }
func (tx *ArbitrumLegacyTxData) to() *common.Address { return tx.To }

func (tx *ArbitrumLegacyTxData) isFake() bool { return false }

func (tx *ArbitrumLegacyTxData) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}
func (tx *ArbitrumLegacyTxData) txType() byte { return ArbitrumLegacyTxType }

func (tx *ArbitrumLegacyTxData) setSignatureValues(chainID, v, r, s *big.Int) {
tx.V, tx.R, tx.S = v, r, s
func (tx *ArbitrumLegacyTxData) EncodeOnlyLegacyInto(w *bytes.Buffer) {
rlp.Encode(w, tx.LegacyTx)
}
12 changes: 12 additions & 0 deletions core/types/arbitrum_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func (s arbitrumSigner) Sender(tx *Transaction) (common.Address, error) {
return inner.From, nil
case *ArbitrumSubmitRetryableTx:
return inner.From, nil
case *ArbitrumLegacyTxData:
legacyData := tx.inner.(*ArbitrumLegacyTxData)
fakeTx := NewTx(&legacyData.LegacyTx)
return s.Signer.Sender(fakeTx)
default:
return s.Signer.Sender(tx)
}
Expand All @@ -56,6 +60,10 @@ func (s arbitrumSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *b
return bigZero, bigZero, bigZero, nil
case *ArbitrumSubmitRetryableTx:
return bigZero, bigZero, bigZero, nil
case *ArbitrumLegacyTxData:
legacyData := tx.inner.(*ArbitrumLegacyTxData)
fakeTx := NewTx(&legacyData.LegacyTx)
return s.Signer.SignatureValues(fakeTx, sig)
default:
return s.Signer.SignatureValues(tx, sig)
}
Expand All @@ -64,5 +72,9 @@ func (s arbitrumSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *b
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s arbitrumSigner) Hash(tx *Transaction) common.Hash {
if legacyData, isArbLegacy := tx.inner.(*ArbitrumLegacyTxData); isArbLegacy {
fakeTx := NewTx(&legacyData.LegacyTx)
return s.Signer.Hash(fakeTx)
}
return s.Signer.Hash(tx)
}
81 changes: 65 additions & 16 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
var (
receiptStatusFailedRLP = []byte{}
receiptStatusSuccessfulRLP = []byte{0x01}
receiptRootArbitrumLegacy = []byte{0x00}
)

var errShortTypedReceipt = errors.New("typed receipt too short")
Expand All @@ -52,7 +53,7 @@ const (
type Receipt struct {
// Arbitrum Implementation fields
GasUsedForL1 uint64 `json:"gasUsedForL1"`

// Consensus fields: These fields are defined by the Yellow Paper
Type uint8 `json:"type,omitempty"`
PostState []byte `json:"root"`
Expand Down Expand Up @@ -103,6 +104,16 @@ type storedReceiptRLP struct {
Logs []*LogForStorage
}

type arbLegacyStoredReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
GasUsed uint64
L1GasUsed uint64
Status uint64
ContractAddress common.Address
Logs []*LogForStorage
}

// v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
type v4StoredReceiptRLP struct {
PostStateOrStatus []byte
Expand Down Expand Up @@ -283,9 +294,18 @@ type ReceiptForStorage Receipt
func (r *ReceiptForStorage) EncodeRLP(_w io.Writer) error {
w := rlp.NewEncoderBuffer(_w)
outerList := w.List()
w.WriteBytes((*Receipt)(r).statusEncoding())
w.WriteUint64(r.CumulativeGasUsed)
w.WriteUint64(r.GasUsedForL1)
if r.Type == ArbitrumLegacyTxType {
w.WriteBytes(receiptRootArbitrumLegacy)
w.WriteUint64(r.CumulativeGasUsed)
w.WriteUint64(r.GasUsed)
w.WriteUint64(r.GasUsedForL1)
w.WriteUint64(r.Status)
rlp.Encode(w, r.ContractAddress)
} else {
w.WriteBytes((*Receipt)(r).statusEncoding())
w.WriteUint64(r.CumulativeGasUsed)
w.WriteUint64(r.GasUsedForL1)
}
logList := w.List()
for _, log := range r.Logs {
if err := rlp.Encode(w, log); err != nil {
Expand All @@ -311,12 +331,39 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
if err := decodeStoredReceiptRLP(r, blob); err == nil {
return nil
}
if err := decodeArbitrumLegacyStoredReceiptRLP(r, blob); err == nil {
return nil
}
if err := decodeV3StoredReceiptRLP(r, blob); err == nil {
return nil
}
return decodeV4StoredReceiptRLP(r, blob)
}

func decodeArbitrumLegacyStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
var stored arbLegacyStoredReceiptRLP
if err := rlp.DecodeBytes(blob, &stored); err != nil {
return err
}
if !bytes.Equal(stored.PostStateOrStatus, receiptRootArbitrumLegacy) {
return errors.New("not arbitrum legacy Tx")
}
r.Type = ArbitrumLegacyTxType
(*Receipt)(r).PostState = receiptRootArbitrumLegacy
r.Status = stored.Status
r.CumulativeGasUsed = stored.CumulativeGasUsed
r.GasUsed = stored.GasUsed
r.GasUsedForL1 = stored.L1GasUsed
r.ContractAddress = stored.ContractAddress
r.Logs = make([]*Log, len(stored.Logs))
for i, log := range stored.Logs {
r.Logs[i] = (*Log)(log)
}
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})

return nil
}

func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
var stored storedReceiptRLP
if err := rlp.DecodeBytes(blob, &stored); err != nil {
Expand Down Expand Up @@ -388,7 +435,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
r := rs[i]
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
switch r.Type {
case LegacyTxType:
case LegacyTxType, ArbitrumLegacyTxType:
rlp.Encode(w, data)
default:
w.WriteByte(r.Type)
Expand All @@ -415,17 +462,19 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu
rs[i].BlockNumber = new(big.Int).SetUint64(number)
rs[i].TransactionIndex = uint(i)

// The contract address can be derived from the transaction itself
if txs[i].To() == nil {
// Deriving the signer is expensive, only do if it's actually needed
from, _ := Sender(signer, txs[i])
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
}
// The used gas can be calculated based on previous r
if i == 0 {
rs[i].GasUsed = rs[i].CumulativeGasUsed
} else {
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
if rs[i].Type != ArbitrumLegacyTxType {
// The contract address can be derived from the transaction itself
if txs[i].To() == nil {
// Deriving the signer is expensive, only do if it's actually needed
from, _ := Sender(signer, txs[i])
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
}
// The used gas can be calculated based on previous r
if i == 0 {
rs[i].GasUsed = rs[i].CumulativeGasUsed
} else {
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
}
}
// The derived log fields can simply be set from the block and transaction
for j := 0; j < len(rs[i].Logs); j++ {
Expand Down
5 changes: 4 additions & 1 deletion core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func (tx *Transaction) Hash() common.Hash {
if tx.Type() == LegacyTxType {
h = rlpHash(tx.inner)
} else if tx.Type() == ArbitrumLegacyTxType {
h = tx.inner.(*ArbitrumLegacyTxData).Hash
h = tx.inner.(*ArbitrumLegacyTxData).HashOverride
} else {
h = prefixedRlpHash(tx.Type(), tx.inner)
}
Expand Down Expand Up @@ -460,6 +460,9 @@ func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) {
tx := s[i]
if tx.Type() == LegacyTxType {
rlp.Encode(w, tx.inner)
} else if tx.Type() == ArbitrumLegacyTxType {
arbData := tx.inner.(*ArbitrumLegacyTxData)
arbData.EncodeOnlyLegacyInto(w)
} else {
tx.encodeTyped(w)
}
Expand Down
Loading