gofmt rollup packages (#556)

This commit is contained in:
HAOYUatHZ 2023-11-08 16:25:02 +08:00 committed by GitHub
parent 94995b7e10
commit 76756cea1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 174 deletions

View file

@ -1,145 +1,145 @@
package fees package fees
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/types" "github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/params" "github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/rollup/rcfg" "github.com/scroll-tech/go-ethereum/rollup/rcfg"
) )
var ( var (
// txExtraDataBytes is the number of bytes that we commit to L1 in addition // txExtraDataBytes is the number of bytes that we commit to L1 in addition
// to the RLP-encoded signed transaction. Note that these are all assumed // to the RLP-encoded signed transaction. Note that these are all assumed
// to be non-zero. // to be non-zero.
// - tx length prefix: 4 bytes // - tx length prefix: 4 bytes
txExtraDataBytes = uint64(4) txExtraDataBytes = uint64(4)
) )
// Message represents the interface of a message. // Message represents the interface of a message.
// It should be a subset of the methods found on // It should be a subset of the methods found on
// types.Message // types.Message
type Message interface { type Message interface {
From() common.Address From() common.Address
To() *common.Address To() *common.Address
GasPrice() *big.Int GasPrice() *big.Int
Gas() uint64 Gas() uint64
GasFeeCap() *big.Int GasFeeCap() *big.Int
GasTipCap() *big.Int GasTipCap() *big.Int
Value() *big.Int Value() *big.Int
Nonce() uint64 Nonce() uint64
Data() []byte Data() []byte
AccessList() types.AccessList AccessList() types.AccessList
IsL1MessageTx() bool IsL1MessageTx() bool
} }
// StateDB represents the StateDB interface // StateDB represents the StateDB interface
// required to compute the L1 fee // required to compute the L1 fee
type StateDB interface { type StateDB interface {
GetState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash
GetBalance(addr common.Address) *big.Int GetBalance(addr common.Address) *big.Int
} }
func EstimateL1DataFeeForMessage(msg Message, baseFee, chainID *big.Int, signer types.Signer, state StateDB) (*big.Int, error) { func EstimateL1DataFeeForMessage(msg Message, baseFee, chainID *big.Int, signer types.Signer, state StateDB) (*big.Int, error) {
if msg.IsL1MessageTx() { if msg.IsL1MessageTx() {
return big.NewInt(0), nil return big.NewInt(0), nil
} }
unsigned := asUnsignedTx(msg, baseFee, chainID) unsigned := asUnsignedTx(msg, baseFee, chainID)
// with v=1 // with v=1
tx, err := unsigned.WithSignature(signer, append(bytes.Repeat([]byte{0xff}, crypto.SignatureLength-1), 0x01)) tx, err := unsigned.WithSignature(signer, append(bytes.Repeat([]byte{0xff}, crypto.SignatureLength-1), 0x01))
if err != nil { if err != nil {
return nil, err return nil, err
} }
raw, err := rlpEncode(tx) raw, err := rlpEncode(tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state) l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar) l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
return l1DataFee, nil return l1DataFee, nil
} }
// asUnsignedTx turns a Message into a types.Transaction // asUnsignedTx turns a Message into a types.Transaction
func asUnsignedTx(msg Message, baseFee, chainID *big.Int) *types.Transaction { func asUnsignedTx(msg Message, baseFee, chainID *big.Int) *types.Transaction {
if baseFee == nil { if baseFee == nil {
if msg.AccessList() == nil { if msg.AccessList() == nil {
return asUnsignedLegacyTx(msg) return asUnsignedLegacyTx(msg)
} }
return asUnsignedAccessListTx(msg, chainID) return asUnsignedAccessListTx(msg, chainID)
} }
return asUnsignedDynamicTx(msg, chainID) return asUnsignedDynamicTx(msg, chainID)
} }
func asUnsignedLegacyTx(msg Message) *types.Transaction { func asUnsignedLegacyTx(msg Message) *types.Transaction {
return types.NewTx(&types.LegacyTx{ return types.NewTx(&types.LegacyTx{
Nonce: msg.Nonce(), Nonce: msg.Nonce(),
To: msg.To(), To: msg.To(),
Value: msg.Value(), Value: msg.Value(),
Gas: msg.Gas(), Gas: msg.Gas(),
GasPrice: msg.GasPrice(), GasPrice: msg.GasPrice(),
Data: msg.Data(), Data: msg.Data(),
}) })
} }
func asUnsignedAccessListTx(msg Message, chainID *big.Int) *types.Transaction { func asUnsignedAccessListTx(msg Message, chainID *big.Int) *types.Transaction {
return types.NewTx(&types.AccessListTx{ return types.NewTx(&types.AccessListTx{
Nonce: msg.Nonce(), Nonce: msg.Nonce(),
To: msg.To(), To: msg.To(),
Value: msg.Value(), Value: msg.Value(),
Gas: msg.Gas(), Gas: msg.Gas(),
GasPrice: msg.GasPrice(), GasPrice: msg.GasPrice(),
Data: msg.Data(), Data: msg.Data(),
AccessList: msg.AccessList(), AccessList: msg.AccessList(),
ChainID: chainID, ChainID: chainID,
}) })
} }
func asUnsignedDynamicTx(msg Message, chainID *big.Int) *types.Transaction { func asUnsignedDynamicTx(msg Message, chainID *big.Int) *types.Transaction {
return types.NewTx(&types.DynamicFeeTx{ return types.NewTx(&types.DynamicFeeTx{
Nonce: msg.Nonce(), Nonce: msg.Nonce(),
To: msg.To(), To: msg.To(),
Value: msg.Value(), Value: msg.Value(),
Gas: msg.Gas(), Gas: msg.Gas(),
GasFeeCap: msg.GasFeeCap(), GasFeeCap: msg.GasFeeCap(),
GasTipCap: msg.GasTipCap(), GasTipCap: msg.GasTipCap(),
Data: msg.Data(), Data: msg.Data(),
AccessList: msg.AccessList(), AccessList: msg.AccessList(),
ChainID: chainID, ChainID: chainID,
}) })
} }
// rlpEncode RLP encodes the transaction into bytes // rlpEncode RLP encodes the transaction into bytes
func rlpEncode(tx *types.Transaction) ([]byte, error) { func rlpEncode(tx *types.Transaction) ([]byte, error) {
raw := new(bytes.Buffer) raw := new(bytes.Buffer)
if err := tx.EncodeRLP(raw); err != nil { if err := tx.EncodeRLP(raw); err != nil {
return nil, err return nil, err
} }
return raw.Bytes(), nil return raw.Bytes(), nil
} }
func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Int) { func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Int) {
l1BaseFee := state.GetState(addr, rcfg.L1BaseFeeSlot) l1BaseFee := state.GetState(addr, rcfg.L1BaseFeeSlot)
overhead := state.GetState(addr, rcfg.OverheadSlot) overhead := state.GetState(addr, rcfg.OverheadSlot)
scalar := state.GetState(addr, rcfg.ScalarSlot) scalar := state.GetState(addr, rcfg.ScalarSlot)
return l1BaseFee.Big(), overhead.Big(), scalar.Big() return l1BaseFee.Big(), overhead.Big(), scalar.Big()
} }
// calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx // calculateEncodedL1DataFee computes the L1 fee for an RLP-encoded tx
func calculateEncodedL1DataFee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Int) *big.Int { func calculateEncodedL1DataFee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Int) *big.Int {
l1GasUsed := CalculateL1GasUsed(data, overhead) l1GasUsed := CalculateL1GasUsed(data, overhead)
l1DataFee := new(big.Int).Mul(l1GasUsed, l1GasPrice) l1DataFee := new(big.Int).Mul(l1GasUsed, l1GasPrice)
return mulAndScale(l1DataFee, scalar, rcfg.Precision) return mulAndScale(l1DataFee, scalar, rcfg.Precision)
} }
// CalculateL1GasUsed computes the L1 gas used based on the calldata and // CalculateL1GasUsed computes the L1 gas used based on the calldata and
@ -147,79 +147,79 @@ func calculateEncodedL1DataFee(data []byte, overhead, l1GasPrice *big.Int, scala
// batch submission goes down via contract optimizations. This will not overflow // batch submission goes down via contract optimizations. This will not overflow
// under standard network conditions. // under standard network conditions.
func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int { func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int {
zeroes, ones := zeroesAndOnes(data) zeroes, ones := zeroesAndOnes(data)
zeroesGas := zeroes * params.TxDataZeroGas zeroesGas := zeroes * params.TxDataZeroGas
onesGas := (ones + txExtraDataBytes) * params.TxDataNonZeroGasEIP2028 onesGas := (ones + txExtraDataBytes) * params.TxDataNonZeroGasEIP2028
l1Gas := new(big.Int).SetUint64(zeroesGas + onesGas) l1Gas := new(big.Int).SetUint64(zeroesGas + onesGas)
return new(big.Int).Add(l1Gas, overhead) return new(big.Int).Add(l1Gas, overhead)
} }
// zeroesAndOnes counts the number of 0 bytes and non 0 bytes in a byte slice // zeroesAndOnes counts the number of 0 bytes and non 0 bytes in a byte slice
func zeroesAndOnes(data []byte) (uint64, uint64) { func zeroesAndOnes(data []byte) (uint64, uint64) {
var zeroes uint64 var zeroes uint64
var ones uint64 var ones uint64
for _, byt := range data { for _, byt := range data {
if byt == 0 { if byt == 0 {
zeroes++ zeroes++
} else { } else {
ones++ ones++
} }
} }
return zeroes, ones return zeroes, ones
} }
// mulAndScale multiplies a big.Int by a big.Int and then scale it by precision, // mulAndScale multiplies a big.Int by a big.Int and then scale it by precision,
// rounded towards zero // rounded towards zero
func mulAndScale(x *big.Int, y *big.Int, precision *big.Int) *big.Int { func mulAndScale(x *big.Int, y *big.Int, precision *big.Int) *big.Int {
z := new(big.Int).Mul(x, y) z := new(big.Int).Mul(x, y)
return new(big.Int).Quo(z, precision) return new(big.Int).Quo(z, precision)
} }
func CalculateL1DataFee(tx *types.Transaction, state StateDB) (*big.Int, error) { func CalculateL1DataFee(tx *types.Transaction, state StateDB) (*big.Int, error) {
if tx.IsL1MessageTx() { if tx.IsL1MessageTx() {
return big.NewInt(0), nil return big.NewInt(0), nil
} }
raw, err := rlpEncode(tx) raw, err := rlpEncode(tx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state) l1BaseFee, overhead, scalar := readGPOStorageSlots(rcfg.L1GasPriceOracleAddress, state)
l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar) l1DataFee := calculateEncodedL1DataFee(raw, overhead, l1BaseFee, scalar)
return l1DataFee, nil return l1DataFee, nil
} }
func calculateL2Fee(tx *types.Transaction) *big.Int { func calculateL2Fee(tx *types.Transaction) *big.Int {
l2GasLimit := new(big.Int).SetUint64(tx.Gas()) l2GasLimit := new(big.Int).SetUint64(tx.Gas())
return new(big.Int).Mul(tx.GasPrice(), l2GasLimit) return new(big.Int).Mul(tx.GasPrice(), l2GasLimit)
} }
func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error { func VerifyFee(signer types.Signer, tx *types.Transaction, state StateDB) error {
from, err := types.Sender(signer, tx) from, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return errors.New("invalid transaction: invalid sender") return errors.New("invalid transaction: invalid sender")
} }
balance := state.GetBalance(from) balance := state.GetBalance(from)
l2Fee := calculateL2Fee(tx) l2Fee := calculateL2Fee(tx)
l1DataFee, err := CalculateL1DataFee(tx, state) l1DataFee, err := CalculateL1DataFee(tx, state)
if err != nil { if err != nil {
return fmt.Errorf("invalid transaction: %w", err) return fmt.Errorf("invalid transaction: %w", err)
} }
cost := tx.Value() cost := tx.Value()
cost = cost.Add(cost, l2Fee) cost = cost.Add(cost, l2Fee)
if balance.Cmp(cost) < 0 { if balance.Cmp(cost) < 0 {
return errors.New("invalid transaction: insufficient funds for gas * price + value") return errors.New("invalid transaction: insufficient funds for gas * price + value")
} }
cost = cost.Add(cost, l1DataFee) cost = cost.Add(cost, l1DataFee)
if balance.Cmp(cost) < 0 { if balance.Cmp(cost) < 0 {
return errors.New("invalid transaction: insufficient funds for l1fee + gas * price + value") return errors.New("invalid transaction: insufficient funds for l1fee + gas * price + value")
} }
// TODO: check GasPrice is in an expected range // TODO: check GasPrice is in an expected range
return nil return nil
} }

View file

@ -1,20 +1,20 @@
package fees package fees
import ( import (
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCalculateEncodedL1DataFee(t *testing.T) { func TestCalculateEncodedL1DataFee(t *testing.T) {
l1BaseFee := new(big.Int).SetUint64(15000000) l1BaseFee := new(big.Int).SetUint64(15000000)
data := []byte{0, 10, 1, 0} data := []byte{0, 10, 1, 0}
overhead := new(big.Int).SetUint64(100) overhead := new(big.Int).SetUint64(100)
scalar := new(big.Int).SetUint64(10) scalar := new(big.Int).SetUint64(10)
expected := new(big.Int).SetUint64(184) // 184.2 expected := new(big.Int).SetUint64(184) // 184.2
actual := calculateEncodedL1DataFee(data, overhead, l1BaseFee, scalar) actual := calculateEncodedL1DataFee(data, overhead, l1BaseFee, scalar)
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }

View file

@ -1,32 +1,32 @@
package rcfg package rcfg
import ( import (
"math/big" "math/big"
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
) )
// TODO: // TODO:
// verify in consensus layer when decentralizing sequencer // verify in consensus layer when decentralizing sequencer
var ( var (
// L2MessageQueueAddress is the address of the L2MessageQueue // L2MessageQueueAddress is the address of the L2MessageQueue
// predeploy // predeploy
// see contracts/src/L2/predeploys/L2MessageQueue.sol // see contracts/src/L2/predeploys/L2MessageQueue.sol
L2MessageQueueAddress = common.HexToAddress("0x5300000000000000000000000000000000000000") L2MessageQueueAddress = common.HexToAddress("0x5300000000000000000000000000000000000000")
WithdrawTrieRootSlot = common.BigToHash(big.NewInt(0)) WithdrawTrieRootSlot = common.BigToHash(big.NewInt(0))
// ScrollFeeVaultAddress is the address of the L2TxFeeVault // ScrollFeeVaultAddress is the address of the L2TxFeeVault
// predeploy // predeploy
// see scroll-tech/scroll/contracts/src/L2/predeploys/L2TxFeeVault.sol // see scroll-tech/scroll/contracts/src/L2/predeploys/L2TxFeeVault.sol
ScrollFeeVaultAddress = common.HexToAddress("0x5300000000000000000000000000000000000005") ScrollFeeVaultAddress = common.HexToAddress("0x5300000000000000000000000000000000000005")
// L1GasPriceOracleAddress is the address of the L1GasPriceOracle // L1GasPriceOracleAddress is the address of the L1GasPriceOracle
// predeploy // predeploy
// see scroll-tech/scroll/contracts/src/L2/predeploys/L1GasPriceOracle.sol // see scroll-tech/scroll/contracts/src/L2/predeploys/L1GasPriceOracle.sol
L1GasPriceOracleAddress = common.HexToAddress("0x5300000000000000000000000000000000000002") L1GasPriceOracleAddress = common.HexToAddress("0x5300000000000000000000000000000000000002")
Precision = new(big.Int).SetUint64(1e9) Precision = new(big.Int).SetUint64(1e9)
L1BaseFeeSlot = common.BigToHash(big.NewInt(1)) L1BaseFeeSlot = common.BigToHash(big.NewInt(1))
OverheadSlot = common.BigToHash(big.NewInt(2)) OverheadSlot = common.BigToHash(big.NewInt(2))
ScalarSlot = common.BigToHash(big.NewInt(3)) ScalarSlot = common.BigToHash(big.NewInt(3))
) )

View file

@ -1,18 +1,18 @@
package withdrawtrie package withdrawtrie
import ( import (
"github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/rollup/rcfg" "github.com/scroll-tech/go-ethereum/rollup/rcfg"
) )
// StateDB represents the StateDB interface // StateDB represents the StateDB interface
// required to get withdraw trie root // required to get withdraw trie root
type StateDB interface { type StateDB interface {
GetState(common.Address, common.Hash) common.Hash GetState(common.Address, common.Hash) common.Hash
} }
// ReadWTRSlot reads WithdrawTrieRoot slot in L2MessageQueue predeploy, i.e., `messageRoot` // ReadWTRSlot reads WithdrawTrieRoot slot in L2MessageQueue predeploy, i.e., `messageRoot`
// in contracts/src/libraries/common/AppendOnlyMerkleTree.sol // in contracts/src/libraries/common/AppendOnlyMerkleTree.sol
func ReadWTRSlot(addr common.Address, state StateDB) common.Hash { func ReadWTRSlot(addr common.Address, state StateDB) common.Hash {
return state.GetState(addr, rcfg.WithdrawTrieRootSlot) return state.GetState(addr, rcfg.WithdrawTrieRootSlot)
} }