Skip to content

Commit

Permalink
Merge pull request ethereum#42 from OffchainLabs/gas-margin-plus-retr…
Browse files Browse the repository at this point in the history
…yables

Gas margin plus retryables
  • Loading branch information
edfelten authored Jan 22, 2022
2 parents aae2f2d + 4723c73 commit 3fcac93
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 43 deletions.
12 changes: 11 additions & 1 deletion accounts/abi/bind/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type TransactOpts struct {
GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
GasMargin uint64 // Arbitrum: adjusts gas estimate by this many basis points (0 = no adjustment)

Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)

Expand Down Expand Up @@ -344,7 +345,16 @@ func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Ad
Value: value,
Data: input,
}
return c.transactor.EstimateGas(ensureContext(opts.Context), msg)
gasLimit, err := c.transactor.EstimateGas(ensureContext(opts.Context), msg)
if err != nil {
return 0, err
}
// Arbitrum: adjust the estimate
adjustedLimit := gasLimit * (10000 + opts.GasMargin) / 10000
if adjustedLimit > gasLimit {
gasLimit = adjustedLimit
}
return gasLimit, nil
}

func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) {
Expand Down
31 changes: 14 additions & 17 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,14 +364,13 @@ func (st *StateTransition) transitionDbImpl() (*ExecutionResult, error) {

func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {

isDeposit := st.evm.ProcessingHook.StartTxHook()
if isDeposit {
res := &ExecutionResult{
UsedGas: 0,
Err: nil,
ReturnData: nil,
}
return res, nil
endTxNow, usedGas, err, returnData := st.evm.ProcessingHook.StartTxHook()
if endTxNow {
return &ExecutionResult{
UsedGas: usedGas,
Err: err,
ReturnData: returnData,
}, nil
}

res, err := st.transitionDbImpl()
Expand All @@ -393,16 +392,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
func (st *StateTransition) refundGas(refundQuotient uint64) {

nonrefundable := st.evm.ProcessingHook.NonrefundableGas()
if nonrefundable >= st.gasUsed() {
return
}

// Apply refund counter, capped to a refund quotient
refund := (st.gasUsed() - nonrefundable) / refundQuotient
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
if nonrefundable < st.gasUsed() {
// Apply refund counter, capped to a refund quotient
refund := (st.gasUsed() - nonrefundable) / refundQuotient
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
st.gas += refund
}
st.gas += refund

// Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
Expand Down
67 changes: 47 additions & 20 deletions core/types/arb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,38 +131,65 @@ func (tx *ArbitrumContractTx) setSignatureValues(chainID, v, r, s *big.Int) {}
func (tx *ArbitrumContractTx) isFake() bool { return true }

type ArbitrumRetryTx struct {
ArbitrumContractTx
ChainId *big.Int
Nonce uint64
From common.Address

GasPrice *big.Int // wei per gas
Gas uint64 // gas limit
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int // wei amount
Data []byte // contract invocation input data
TicketId common.Hash
RefundTo common.Address
}

func (tx *ArbitrumRetryTx) txType() byte { return ArbitrumRetryTxType }

func (tx *ArbitrumRetryTx) copy() TxData {
return &ArbitrumRetryTx{
*tx.ArbitrumContractTx.copy().(*ArbitrumContractTx),
tx.TicketId,
tx.RefundTo,
cpy := &ArbitrumRetryTx{
ChainId: new(big.Int),
Nonce: tx.Nonce,
GasPrice: new(big.Int),
Gas: tx.Gas,
From: tx.From,
To: nil,
Value: new(big.Int),
Data: common.CopyBytes(tx.Data),
TicketId: tx.TicketId,
RefundTo: tx.RefundTo,
}
if tx.ChainId != nil {
cpy.ChainId.Set(tx.ChainId)
}
if tx.GasPrice != nil {
cpy.GasPrice.Set(tx.GasPrice)
}
if tx.To != nil {
tmp := *tx.To
cpy.To = &tmp
}
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
return cpy
}

func (tx *ArbitrumRetryTx) chainID() *big.Int { return tx.ArbitrumContractTx.chainID() }
func (tx *ArbitrumRetryTx) accessList() AccessList { return tx.ArbitrumContractTx.accessList() }
func (tx *ArbitrumRetryTx) data() []byte { return tx.ArbitrumContractTx.data() }
func (tx *ArbitrumRetryTx) gas() uint64 { return tx.ArbitrumContractTx.gas() }
func (tx *ArbitrumRetryTx) gasPrice() *big.Int { return tx.ArbitrumContractTx.gasPrice() }
func (tx *ArbitrumRetryTx) gasTipCap() *big.Int { return tx.ArbitrumContractTx.gasTipCap() }
func (tx *ArbitrumRetryTx) gasFeeCap() *big.Int { return tx.ArbitrumContractTx.gasFeeCap() }
func (tx *ArbitrumRetryTx) value() *big.Int { return tx.ArbitrumContractTx.value() }
func (tx *ArbitrumRetryTx) nonce() uint64 { return tx.ArbitrumContractTx.nonce() }
func (tx *ArbitrumRetryTx) to() *common.Address { return tx.ArbitrumContractTx.to() }
func (tx *ArbitrumRetryTx) chainID() *big.Int { return tx.ChainId }
func (tx *ArbitrumRetryTx) accessList() AccessList { return nil }
func (tx *ArbitrumRetryTx) data() []byte { return tx.Data }
func (tx *ArbitrumRetryTx) gas() uint64 { return tx.Gas }
func (tx *ArbitrumRetryTx) gasPrice() *big.Int { return tx.GasPrice }
func (tx *ArbitrumRetryTx) gasTipCap() *big.Int { return tx.GasPrice }
func (tx *ArbitrumRetryTx) gasFeeCap() *big.Int { return tx.GasPrice }
func (tx *ArbitrumRetryTx) value() *big.Int { return tx.Value }
func (tx *ArbitrumRetryTx) nonce() uint64 { return tx.Nonce }
func (tx *ArbitrumRetryTx) to() *common.Address { return tx.To }
func (tx *ArbitrumRetryTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.ArbitrumContractTx.rawSignatureValues()
}
func (tx *ArbitrumRetryTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ArbitrumContractTx.setSignatureValues(chainID, v, r, s)
return bigZero, bigZero, bigZero
}
func (tx *ArbitrumRetryTx) isFake() bool { return true }
func (tx *ArbitrumRetryTx) setSignatureValues(chainID, v, r, s *big.Int) {}
func (tx *ArbitrumRetryTx) isFake() bool { return true }

type ArbitrumSubmitRetryableTx struct {
ChainId *big.Int
Expand Down
2 changes: 0 additions & 2 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,6 @@ func (tx *Transaction) Hash() common.Hash {
h = rlpHash(tx.inner)
} else if tx.Type() == ArbitrumSubmitRetryableTxType {
h = tx.inner.(*ArbitrumSubmitRetryableTx).RequestId // this is required by the retryables API
} else if tx.Type() == ArbitrumRetryTxType {
h = tx.inner.(*ArbitrumRetryTx).RequestId // for this type, RequestId was initialized with the desired tx hash
} else {
h = prefixedRlpHash(tx.Type(), tx.inner)
}
Expand Down
6 changes: 3 additions & 3 deletions core/vm/evm_arbitrum.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (evm *EVM) Depth() int {
}

type TxProcessingHook interface {
StartTxHook() bool
StartTxHook() (bool, uint64, error, []byte) // return 4-tuple rather than *struct to avoid an import cycle
GasChargingHook(gasRemaining *uint64) error
EndTxHook(totalGasUsed uint64, success bool)
NonrefundableGas() uint64
Expand All @@ -38,8 +38,8 @@ type TxProcessingHook interface {

type DefaultTxProcessor struct{}

func (p DefaultTxProcessor) StartTxHook() bool {
return false
func (p DefaultTxProcessor) StartTxHook() (bool, uint64, error, []byte) {
return false, 0, nil, nil
}

func (p DefaultTxProcessor) GasChargingHook(gasRemaining *uint64) error {
Expand Down

0 comments on commit 3fcac93

Please sign in to comment.