Skip to content

Commit 127a870

Browse files
authored
Merge pull request #3 from OffchainLabs/arb-tx
Arb tx and hook
2 parents 9aae462 + 034d9ba commit 127a870

File tree

6 files changed

+273
-14
lines changed

6 files changed

+273
-14
lines changed

core/state_transition.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ import (
3232

3333
var emptyCodeHash = crypto.Keccak256Hash(nil)
3434

35+
type TxProcessingHook interface {
36+
InterceptMessage() (*ExecutionResult, error)
37+
ExtraGasChargingHook(gasRemaining *uint64, gasPool *GasPool) error
38+
EndTxHook(totalGasUsed uint64, gasPool *GasPool, success bool) error
39+
}
40+
3541
/*
3642
The State Transitioning Model
3743
@@ -50,7 +56,7 @@ The state transitioning model does all the necessary work to work out a valid ne
5056
6) Derive new state root
5157
*/
5258
type StateTransition struct {
53-
extraGasUsedByHook uint64
59+
processingHook TxProcessingHook
5460

5561
gp *GasPool
5662
msg Message
@@ -158,9 +164,13 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
158164
return gas, nil
159165
}
160166

167+
var CreateTxProcessingHook func(msg Message, evm *vm.EVM) TxProcessingHook
168+
161169
// NewStateTransition initialises and returns a new state transition object.
162170
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
163171
return &StateTransition{
172+
processingHook: CreateTxProcessingHook(msg, evm),
173+
164174
gp: gp,
165175
evm: evm,
166176
msg: msg,
@@ -259,9 +269,6 @@ func (st *StateTransition) preCheck() error {
259269
return st.buyGas()
260270
}
261271

262-
var ExtraGasChargingHook func(msg Message, txGasRemaining *uint64, gasPool *GasPool, state vm.StateDB) error
263-
var EndTxHook func(msg Message, totalGasUsed uint64, extraGasCharged uint64, gasPool *GasPool, success bool, state vm.StateDB) error
264-
265272
// TransitionDb will transition the state by applying the current message and
266273
// returning the evm execution result with following fields.
267274
//
@@ -307,12 +314,8 @@ func (st *StateTransition) transitionDbImpl() (*ExecutionResult, error) {
307314
}
308315
st.gas -= gas
309316

310-
if ExtraGasChargingHook != nil {
311-
start := st.gas
312-
ExtraGasChargingHook(st.msg, &st.gas, st.gp, st.state)
313-
if start > st.gas {
314-
st.extraGasUsedByHook += start - st.gas
315-
}
317+
if st.processingHook != nil {
318+
st.processingHook.ExtraGasChargingHook(&st.gas, st.gp)
316319
}
317320

318321
// Check clause 6
@@ -357,6 +360,12 @@ func (st *StateTransition) transitionDbImpl() (*ExecutionResult, error) {
357360
}
358361

359362
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
363+
if st.processingHook != nil {
364+
res, err := st.processingHook.InterceptMessage()
365+
if res != nil || err != nil {
366+
return res, err
367+
}
368+
}
360369
res, err := st.transitionDbImpl()
361370
if err != nil && !errors.Is(err, ErrNonceTooLow) && !errors.Is(err, ErrNonceTooHigh) {
362371
res = &ExecutionResult{
@@ -366,8 +375,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
366375
}
367376
err = nil
368377
}
369-
if err == nil && EndTxHook != nil {
370-
EndTxHook(st.msg, st.gas, st.extraGasUsedByHook, st.gp, res.Err == nil, st.state)
378+
379+
if err == nil && st.processingHook != nil {
380+
st.processingHook.EndTxHook(st.gas, st.gp, res.Err == nil)
371381
}
372382
return res, err
373383
}

core/types/arb_types.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package types
2+
3+
import (
4+
"math/big"
5+
6+
"github.com/ethereum/go-ethereum/common"
7+
)
8+
9+
var bigZero = big.NewInt(0)
10+
11+
func (tx *LegacyTx) isFake() bool { return false }
12+
func (tx *AccessListTx) isFake() bool { return false }
13+
func (tx *DynamicFeeTx) isFake() bool { return false }
14+
15+
type ArbitrumUnsignedTx struct {
16+
ChainId *big.Int
17+
From common.Address
18+
19+
Nonce uint64 // nonce of sender account
20+
GasPrice *big.Int // wei per gas
21+
Gas uint64 // gas limit
22+
To *common.Address `rlp:"nil"` // nil means contract creation
23+
Value *big.Int // wei amount
24+
Data []byte // contract invocation input data
25+
}
26+
27+
28+
func (tx *ArbitrumUnsignedTx) txType() byte { return ArbitrumUnsignedTxType }
29+
30+
func (tx *ArbitrumUnsignedTx) copy() TxData {
31+
cpy := &ArbitrumUnsignedTx{
32+
ChainId: new(big.Int),
33+
Nonce: tx.Nonce,
34+
GasPrice: new(big.Int),
35+
Gas: tx.Gas,
36+
To: nil,
37+
Value: new(big.Int),
38+
Data: common.CopyBytes(tx.Data),
39+
}
40+
if tx.ChainId != nil {
41+
cpy.ChainId.Set(tx.ChainId)
42+
}
43+
if tx.GasPrice != nil {
44+
cpy.GasPrice.Set(tx.GasPrice)
45+
}
46+
if tx.To != nil {
47+
tmp := *tx.To
48+
cpy.To = &tmp
49+
}
50+
if tx.Value != nil {
51+
cpy.Value.Set(tx.Value)
52+
}
53+
return cpy
54+
}
55+
56+
func (tx *ArbitrumUnsignedTx) chainID() *big.Int { return tx.ChainId }
57+
func (tx *ArbitrumUnsignedTx) accessList() AccessList { return nil }
58+
func (tx *ArbitrumUnsignedTx) data() []byte { return tx.Data }
59+
func (tx *ArbitrumUnsignedTx) gas() uint64 { return tx.Gas }
60+
func (tx *ArbitrumUnsignedTx) gasPrice() *big.Int { return tx.GasPrice }
61+
func (tx *ArbitrumUnsignedTx) gasTipCap() *big.Int { return tx.GasPrice }
62+
func (tx *ArbitrumUnsignedTx) gasFeeCap() *big.Int { return tx.GasPrice }
63+
func (tx *ArbitrumUnsignedTx) value() *big.Int { return tx.Value }
64+
func (tx *ArbitrumUnsignedTx) nonce() uint64 { return tx.Nonce }
65+
func (tx *ArbitrumUnsignedTx) to() *common.Address { return tx.To }
66+
func (tx *ArbitrumUnsignedTx) isFake() bool { return false }
67+
68+
func (tx *ArbitrumUnsignedTx) rawSignatureValues() (v, r, s *big.Int) {
69+
return bigZero, bigZero, bigZero
70+
}
71+
72+
func (tx *ArbitrumUnsignedTx) setSignatureValues(chainID, v, r, s *big.Int) {
73+
74+
}
75+
76+
type ArbitrumContractTx struct {
77+
ChainId *big.Int
78+
RequestId common.Hash
79+
From common.Address
80+
81+
GasPrice *big.Int // wei per gas
82+
Gas uint64 // gas limit
83+
To *common.Address `rlp:"nil"` // nil means contract creation
84+
Value *big.Int // wei amount
85+
Data []byte // contract invocation input data
86+
}
87+
88+
89+
func (tx *ArbitrumContractTx) txType() byte { return ArbitrumContractTxType }
90+
91+
func (tx *ArbitrumContractTx) copy() TxData {
92+
cpy := &ArbitrumContractTx{
93+
ChainId: new(big.Int),
94+
RequestId: tx.RequestId,
95+
GasPrice: new(big.Int),
96+
Gas: tx.Gas,
97+
To: nil,
98+
Value: new(big.Int),
99+
Data: common.CopyBytes(tx.Data),
100+
}
101+
if tx.ChainId != nil {
102+
cpy.ChainId.Set(tx.ChainId)
103+
}
104+
if tx.GasPrice != nil {
105+
cpy.GasPrice.Set(tx.GasPrice)
106+
}
107+
if tx.To != nil {
108+
tmp := *tx.To
109+
cpy.To = &tmp
110+
}
111+
if tx.Value != nil {
112+
cpy.Value.Set(tx.Value)
113+
}
114+
return cpy
115+
}
116+
117+
func (tx *ArbitrumContractTx) chainID() *big.Int { return tx.ChainId }
118+
func (tx *ArbitrumContractTx) accessList() AccessList { return nil }
119+
func (tx *ArbitrumContractTx) data() []byte { return tx.Data }
120+
func (tx *ArbitrumContractTx) gas() uint64 { return tx.Gas }
121+
func (tx *ArbitrumContractTx) gasPrice() *big.Int { return tx.GasPrice }
122+
func (tx *ArbitrumContractTx) gasTipCap() *big.Int { return tx.GasPrice }
123+
func (tx *ArbitrumContractTx) gasFeeCap() *big.Int { return tx.GasPrice }
124+
func (tx *ArbitrumContractTx) value() *big.Int { return tx.Value }
125+
func (tx *ArbitrumContractTx) nonce() uint64 { return 0 }
126+
func (tx *ArbitrumContractTx) to() *common.Address { return tx.To }
127+
func (tx *ArbitrumContractTx) rawSignatureValues() (v, r, s *big.Int) {
128+
return bigZero, bigZero, bigZero
129+
}
130+
func (tx *ArbitrumContractTx) setSignatureValues(chainID, v, r, s *big.Int) {}
131+
func (tx *ArbitrumContractTx) isFake() bool { return true }
132+
133+
type DepositTx struct {
134+
ChainId *big.Int
135+
L1RequestId common.Hash
136+
To common.Address
137+
Value *big.Int
138+
}
139+
140+
func (d *DepositTx) txType() byte {
141+
return ArbitrumDepositTxType
142+
}
143+
144+
func (d *DepositTx) copy() TxData {
145+
tx := &DepositTx{
146+
ChainId: new(big.Int),
147+
To: d.To,
148+
Value: new(big.Int),
149+
}
150+
if d.ChainId != nil {
151+
tx.ChainId.Set(d.ChainId)
152+
}
153+
if d.Value != nil {
154+
tx.Value.Set(d.Value)
155+
}
156+
return tx
157+
}
158+
159+
func (d *DepositTx) chainID() *big.Int { return d.ChainId }
160+
func (d *DepositTx) accessList() AccessList { return nil }
161+
func (d *DepositTx) data() []byte { return nil }
162+
func (d DepositTx) gas() uint64 { return 0 }
163+
func (d *DepositTx) gasPrice() *big.Int { return bigZero }
164+
func (d *DepositTx) gasTipCap() *big.Int { return bigZero }
165+
func (d *DepositTx) gasFeeCap() *big.Int { return bigZero }
166+
func (d *DepositTx) value() *big.Int { return d.Value }
167+
func (d *DepositTx) nonce() uint64 { return 0 }
168+
func (d *DepositTx) to() *common.Address { return &d.To }
169+
func (d *DepositTx) isFake() bool { return true }
170+
171+
func (d *DepositTx) rawSignatureValues() (v, r, s *big.Int) {
172+
return bigZero, bigZero, bigZero
173+
}
174+
175+
func (d *DepositTx) setSignatureValues(chainID, v, r, s *big.Int) {
176+
177+
}
178+

core/types/arbitrum_signer.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package types
2+
3+
import (
4+
"math/big"
5+
6+
"github.com/ethereum/go-ethereum/common"
7+
)
8+
9+
var arbAddress = common.HexToAddress("0xabc")
10+
11+
type arbitrumSigner struct { Signer }
12+
13+
func NewArbitrumSigner(signer Signer) Signer {
14+
return arbitrumSigner{Signer: signer}
15+
}
16+
17+
func (s arbitrumSigner) Sender(tx *Transaction) (common.Address, error) {
18+
switch inner := tx.inner.(type) {
19+
case *ArbitrumUnsignedTx:
20+
return inner.From, nil
21+
case *ArbitrumContractTx:
22+
return inner.From, nil
23+
case *DepositTx:
24+
return arbAddress, nil
25+
default:
26+
return s.Signer.Sender(tx)
27+
}
28+
}
29+
30+
func (s arbitrumSigner) Equal(s2 Signer) bool {
31+
x, ok := s2.(arbitrumSigner)
32+
return ok && x.Signer.Equal(s.Signer)
33+
}
34+
35+
func (s arbitrumSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
36+
switch tx.inner.(type) {
37+
case *ArbitrumUnsignedTx:
38+
return bigZero, bigZero, bigZero, nil
39+
case *ArbitrumContractTx:
40+
return bigZero, bigZero, bigZero, nil
41+
case *DepositTx:
42+
return bigZero, bigZero, bigZero, nil
43+
default:
44+
return s.Signer.SignatureValues(tx, sig)
45+
}
46+
}
47+
48+
// Hash returns the hash to be signed by the sender.
49+
// It does not uniquely identify the transaction.
50+
func (s arbitrumSigner) Hash(tx *Transaction) common.Hash {
51+
return s.Signer.Hash(tx)
52+
}

core/types/transaction.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ const (
4545
LegacyTxType = iota
4646
AccessListTxType
4747
DynamicFeeTxType
48+
ArbitrumDepositTxType = 200
49+
ArbitrumUnsignedTxType = 201
50+
ArbitrumContractTxType = 202
4851
)
4952

5053
// Transaction is an Ethereum transaction.
@@ -85,6 +88,8 @@ type TxData interface {
8588

8689
rawSignatureValues() (v, r, s *big.Int)
8790
setSignatureValues(chainID, v, r, s *big.Int)
91+
92+
isFake() bool
8893
}
8994

9095
// EncodeRLP implements rlp.Encoder
@@ -569,6 +574,8 @@ func (t *TransactionsByPriceAndNonce) Pop() {
569574
//
570575
// NOTE: In a future PR this will be removed.
571576
type Message struct {
577+
tx *Transaction
578+
572579
to *common.Address
573580
from common.Address
574581
nonce uint64
@@ -601,6 +608,8 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
601608
// AsMessage returns the transaction as a core.Message.
602609
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
603610
msg := Message{
611+
tx: tx,
612+
604613
nonce: tx.Nonce(),
605614
gasLimit: tx.Gas(),
606615
gasPrice: new(big.Int).Set(tx.GasPrice()),
@@ -610,7 +619,7 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
610619
amount: tx.Value(),
611620
data: tx.Data(),
612621
accessList: tx.AccessList(),
613-
isFake: false,
622+
isFake: tx.inner.isFake(),
614623
}
615624
// If baseFee provided, set gasPrice to effectiveGasPrice.
616625
if baseFee != nil {
@@ -621,6 +630,8 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
621630
return msg, err
622631
}
623632

633+
func (m Message) UnderlyingTransaction() *Transaction { return m.tx }
634+
624635
func (m Message) From() common.Address { return m.from }
625636
func (m Message) To() *common.Address { return m.to }
626637
func (m Message) GasPrice() *big.Int { return m.gasPrice }

core/types/transaction_signing.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
5151
default:
5252
signer = FrontierSigner{}
5353
}
54+
if config.IsArbitrum(blockNumber) {
55+
signer = NewArbitrumSigner(signer)
56+
}
5457
return signer
5558
}
5659

0 commit comments

Comments
 (0)