From 0bca8e4b43467cc7dd3f97f90ae588bc72cd8eea Mon Sep 17 00:00:00 2001 From: curryxbo Date: Wed, 1 Feb 2023 17:47:41 +0800 Subject: [PATCH 1/6] adjust gas model --- l2geth/core/state_processor.go | 11 ++- l2geth/core/state_transition.go | 6 ++ l2geth/core/types/receipt.go | 3 + l2geth/eth/gasprice/rollup_gasprice.go | 11 +++ .../fees/bindings/gaspriceoracle_test.go | 13 ++++ l2geth/rollup/fees/rollup_fee.go | 72 +++++++++++++++++++ l2geth/rollup/rcfg/config.go | 6 ++ l2geth/rollup/sync_service.go | 21 ++++++ 8 files changed, 142 insertions(+), 1 deletion(-) diff --git a/l2geth/core/state_processor.go b/l2geth/core/state_processor.go index e5927d998..36c4088bb 100644 --- a/l2geth/core/state_processor.go +++ b/l2geth/core/state_processor.go @@ -127,10 +127,19 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() } *usedGas += gas - // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing whether the root touch-delete accounts. receipt := types.NewReceipt(root, failed, *usedGas) + if fees.DaCharge == 1 { + daFee, daGasPrice, daGasUsed, _, err := fees.DeriveDAGasInfo(msg, statedb) + if err != nil { + return nil, err + } + receipt.DAGasPrice = daGasPrice + receipt.DAFee = daFee + receipt.DAGasUsed = daGasUsed + + } receipt.L1GasPrice = l1GasPrice receipt.L1GasUsed = l1GasUsed receipt.L1Fee = l1Fee diff --git a/l2geth/core/state_transition.go b/l2geth/core/state_transition.go index 13333bf1e..12290c311 100644 --- a/l2geth/core/state_transition.go +++ b/l2geth/core/state_transition.go @@ -69,6 +69,7 @@ type StateTransition struct { evm *vm.EVM // UsingBVM l1Fee *big.Int + daFee *big.Int } // Message represents a message sent to a contract. @@ -131,6 +132,7 @@ func IntrinsicGas(data []byte, contractCreation, isHomestead bool, isEIP2028 boo // NewStateTransition initialises and returns a new state transition object. func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { l1Fee := new(big.Int) + daFee := new(big.Int) gasPrice := msg.GasPrice() if rcfg.UsingBVM { if msg.GasPrice().Cmp(common.Big0) != 0 { @@ -143,6 +145,9 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition } else if charge.Cmp(common.Big1) == 1 { panic(fmt.Sprintf("charge:%v is invaild", charge)) } + if fees.DaCharge == 1 { + daFee, _ = fees.CalculateDAMsgFee(msg, evm.StateDB, nil) + } } } @@ -155,6 +160,7 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition data: msg.Data(), state: evm.StateDB, l1Fee: l1Fee, + daFee: daFee, } } diff --git a/l2geth/core/types/receipt.go b/l2geth/core/types/receipt.go index 1898433e0..00203977c 100644 --- a/l2geth/core/types/receipt.go +++ b/l2geth/core/types/receipt.go @@ -72,6 +72,9 @@ type Receipt struct { L1GasUsed *big.Int `json:"l1GasUsed" gencodec:"required"` L1Fee *big.Int `json:"l1Fee" gencodec:"required"` FeeScalar *big.Float `json:"l1FeeScalar" gencodec:"required"` + DAGasPrice *big.Int `json:"daGasPrice" ` + DAGasUsed *big.Int `json:"daGasUsed" ` + DAFee *big.Int `json:"daFee"` } type receiptMarshaling struct { diff --git a/l2geth/eth/gasprice/rollup_gasprice.go b/l2geth/eth/gasprice/rollup_gasprice.go index a8bf65778..166f5e712 100644 --- a/l2geth/eth/gasprice/rollup_gasprice.go +++ b/l2geth/eth/gasprice/rollup_gasprice.go @@ -14,6 +14,7 @@ import ( type RollupOracle struct { l1GasPrice *big.Int l2GasPrice *big.Int + daGasPrice *big.Int overhead *big.Int scalar *big.Float isBurning *big.Int @@ -21,6 +22,7 @@ type RollupOracle struct { sccAddress common.Address l1GasPriceLock sync.RWMutex l2GasPriceLock sync.RWMutex + daGasPriceLock sync.RWMutex overheadLock sync.RWMutex scalarLock sync.RWMutex isBurningLock sync.RWMutex @@ -74,6 +76,15 @@ func (gpo *RollupOracle) SetL2GasPrice(gasPrice *big.Int) error { return nil } +// SetDAGasPrice returns the current DA gas price +func (gpo *RollupOracle) SetDAGasPrice(daGasPrice *big.Int) error { + gpo.daGasPriceLock.Lock() + defer gpo.daGasPriceLock.Unlock() + gpo.daGasPrice = daGasPrice + log.Info("Set DA Gas Price", "daGasprice", gpo.daGasPrice) + return nil +} + // SuggestOverhead returns the cached overhead value from the // BVM_GasPriceOracle func (gpo *RollupOracle) SuggestOverhead(ctx context.Context) (*big.Int, error) { diff --git a/l2geth/rollup/fees/bindings/gaspriceoracle_test.go b/l2geth/rollup/fees/bindings/gaspriceoracle_test.go index 347a56794..56658a847 100644 --- a/l2geth/rollup/fees/bindings/gaspriceoracle_test.go +++ b/l2geth/rollup/fees/bindings/gaspriceoracle_test.go @@ -28,6 +28,7 @@ func TestCalculateFee(t *testing.T) { opts, _ := NewKeyedTransactor(key) addr, _, gpo, err := DeployGasPriceOracle(opts, sim, opts.From) + // TODO da contract if err != nil { t.Fatal(err) } @@ -88,6 +89,8 @@ func TestCalculateFee(t *testing.T) { gasOracle.SetL1GasPrice(l1BaseFee) gasOracle.SetL2GasPrice(l2GasPrice) + // TODO + //gasOracle.SetDAGasPrice(daGasPrice) gasOracle.SetOverhead(overhead) gasOracle.SetScalar(scalar, decimals) @@ -95,12 +98,22 @@ func TestCalculateFee(t *testing.T) { if err != nil { t.Fatal("cannot get l1 fee") } + // TODO daFee + //daFee, err := gpo.GetDAFee(&callopts, raw.Bytes()) + //if err != nil { + // t.Fatal("cannot get l1 fee") + //} scaled := fees.ScaleDecimals(scalar, decimals) expectL1Fee := fees.CalculateL1Fee(raw.Bytes(), overhead, l1BaseFee, scaled) if expectL1Fee.Cmp(l1Fee) != 0 { t.Fatal("solidity does not match go") } + // TODO + //expectDAFee := fees.CalculateDAFee(raw.Bytes(), overhead, l1BaseFee, scaled) + //if expectL1Fee.Cmp(l1Fee) != 0 { + // t.Fatal("solidity does not match go") + //} state, err := chain.State() if err != nil { diff --git a/l2geth/rollup/fees/rollup_fee.go b/l2geth/rollup/fees/rollup_fee.go index 8f40c236e..2c5b2d50d 100644 --- a/l2geth/rollup/fees/rollup_fee.go +++ b/l2geth/rollup/fees/rollup_fee.go @@ -34,6 +34,8 @@ var ( errTransactionSigned = errors.New("transaction is signed") // big10 is used for decimal scaling big10 = new(big.Int).SetUint64(10) + // TODO replace by contract value + DaCharge = 0 ) // Message represents the interface of a message. @@ -92,6 +94,11 @@ func CalculateTotalFee(tx *types.Transaction, gpo RollupOracle) (*big.Int, error l2GasLimit := new(big.Int).SetUint64(tx.Gas()) l2Fee := new(big.Int).Mul(tx.GasPrice(), l2GasLimit) fee := new(big.Int).Add(l1Fee, l2Fee) + if DaCharge == 1 { + daGasPrice := new(big.Int) + daFee := CalculateDAFee(raw, daGasPrice, scalar) + fee = new(big.Int).Add(fee, daFee) + } return fee, nil } @@ -113,6 +120,13 @@ func CalculateTotalMsgFee(msg Message, state StateDB, gasUsed *big.Int, gpo *com l2Fee := new(big.Int).Mul(msg.GasPrice(), gasUsed) // Add the L1 cost and the L2 cost to get the total fee being paid fee := new(big.Int).Add(l1Fee, l2Fee) + if DaCharge == 1 { + daFee, err := CalculateDAMsgFee(msg, state, gpo) + if err != nil { + return nil, err + } + return new(big.Int).Add(fee, daFee), nil + } return fee, nil } @@ -146,6 +160,9 @@ func CalculateL1Fee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Floa // batch submission goes down via contract optimizations. This will not overflow // under standard network conditions. func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int { + if DaCharge == 1 { + return overhead + } zeroes, ones := zeroesAndOnes(data) zeroesGas := zeroes * params.TxDataZeroGas onesGas := (ones + 68) * params.TxDataNonZeroGasEIP2028 @@ -153,8 +170,46 @@ func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int { return new(big.Int).Add(l1Gas, overhead) } +// CalculateDAMsgFee computes the DA portion of the fee given +// a Message and a StateDB +func CalculateDAMsgFee(msg Message, state StateDB, gpo *common.Address) (*big.Int, error) { + tx := asTransaction(msg) + raw, err := rlpEncode(tx) + if err != nil { + return nil, err + } + + if gpo == nil { + gpo = &rcfg.L2GasPriceOracleAddress + } + + _, _, scalar := readGPOStorageSlots(*gpo, state) + daGasPrice := new(big.Int) + daFee := CalculateDAFee(raw, daGasPrice, scalar) + return daFee, nil +} + +// CalculateDAFee computes the DA fee +func CalculateDAFee(data []byte, daGasPrice *big.Int, scalar *big.Float) *big.Int { + daGasUsed := CalculateDAGasUsed(data) + daFee := new(big.Int).Mul(daGasUsed, daGasPrice) + return mulByFloat(daFee, scalar) +} + +// CalculateDAGasUsed computes the DA gas used based on the calldata and +// constant sized overhead. The overhead can be decreased as the cost of the +// batch submission goes down via contract optimizations. This will not overflow +// under standard network conditions. +func CalculateDAGasUsed(data []byte) *big.Int { + zeroes, ones := zeroesAndOnes(data) + zeroesGas := zeroes * params.TxDataZeroGas + onesGas := (ones + 68) * params.TxDataNonZeroGasEIP2028 + return new(big.Int).SetUint64(zeroesGas + onesGas) +} + // DeriveL1GasInfo reads L1 gas related information to be included // on the receipt +// TODO DONE func DeriveL1GasInfo(msg Message, state StateDB) (*big.Int, *big.Int, *big.Int, *big.Float, error) { tx := asTransaction(msg) raw, err := rlpEncode(tx) @@ -168,6 +223,23 @@ func DeriveL1GasInfo(msg Message, state StateDB) (*big.Int, *big.Int, *big.Int, return l1Fee, l1GasPrice, l1GasUsed, scalar, nil } +// DeriveDAGasInfo reads DA gas related information to be included +// on the receipt +// TODO DONE +func DeriveDAGasInfo(msg Message, state StateDB) (*big.Int, *big.Int, *big.Int, *big.Float, error) { + tx := asTransaction(msg) + raw, err := rlpEncode(tx) + if err != nil { + return nil, nil, nil, nil, err + } + _, _, scalar := readGPOStorageSlots(rcfg.L2GasPriceOracleAddress, state) + // TODO delete + daGasPrice := new(big.Int) + daGasUsed := CalculateDAGasUsed(raw) + daFee := CalculateDAFee(raw, daGasPrice, scalar) + return daFee, daGasPrice, daGasUsed, scalar, nil +} + func readGPOStorageSlots(addr common.Address, state StateDB) (*big.Int, *big.Int, *big.Float) { l1GasPrice := state.GetState(addr, rcfg.L1GasPriceSlot) overhead := state.GetState(addr, rcfg.OverheadSlot) diff --git a/l2geth/rollup/rcfg/config.go b/l2geth/rollup/rcfg/config.go index 3ab22a0ac..8edf2748f 100644 --- a/l2geth/rollup/rcfg/config.go +++ b/l2geth/rollup/rcfg/config.go @@ -42,6 +42,12 @@ var ( ChargeSlot = common.BigToHash(big.NewInt(7)) // SccAddressSlot refers to the storage slot in the Scc contract address SccAddressSlot = common.BigToHash(big.NewInt(8)) + // DaGasPriceSlot refers to the storage slot that the da gas price is stored + // in the BVM_GasPriceOracle predeploy + DaGasPriceSlot = common.BigToHash(big.NewInt(9)) + // DaSwitchSlot refers to the storage slot in the BVM_GasPriceOracle that + // holds switch controls whether enable DA + DaSwitchSlot = common.BigToHash(big.NewInt(10)) ) func init() { diff --git a/l2geth/rollup/sync_service.go b/l2geth/rollup/sync_service.go index b392fc2db..6a177e12a 100644 --- a/l2geth/rollup/sync_service.go +++ b/l2geth/rollup/sync_service.go @@ -520,6 +520,17 @@ func (s *SyncService) updateL2GasPrice(statedb *state.StateDB) error { return s.RollupGpo.SetL2GasPrice(value) } +// updateDAGasPrice accepts a state db and reads the gas price from the gas +// price oracle at the state that corresponds to the state db. If no state db +// is passed in, then the tip is used. +func (s *SyncService) updateDAGasPrice(statedb *state.StateDB) error { + value, err := s.readGPOStorageSlot(statedb, rcfg.DaGasPriceSlot) + if err != nil { + return err + } + return s.RollupGpo.SetDAGasPrice(value) +} + // updateOverhead will update the overhead value from the BVM_GasPriceOracle // in the local cache func (s *SyncService) updateOverhead(statedb *state.StateDB) error { @@ -564,6 +575,16 @@ func (s *SyncService) updateCharge(statedb *state.StateDB) error { return s.RollupGpo.SetCharge(charge) } +// updateDASwitch will update the charge value from the BVM_GasPriceOracle +// in the local cache +func (s *SyncService) updateDASwitch(statedb *state.StateDB) error { + daSwitch, err := s.readGPOStorageSlot(statedb, rcfg.DaSwitchSlot) + if err != nil { + return err + } + return s.RollupGpo.SetCharge(daSwitch) +} + // updateSCCAddress will update the sccAddress value from the BVM_GasPriceOracle // in the local cache func (s *SyncService) updateSCCAddress(statedb *state.StateDB) error { From 932334be5fc659677edf56a388c82a98199d10ed Mon Sep 17 00:00:00 2001 From: curryxbo Date: Thu, 2 Feb 2023 10:38:38 +0800 Subject: [PATCH 2/6] update gasPriceOracle contract --- .../L2/predeploys/BVM_GasPriceOracle.sol | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol b/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol index e0ab9e6f5..c4bf46dd4 100644 --- a/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol +++ b/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol @@ -37,6 +37,10 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { uint256 public charge; // sccAddress l1 sccAddress address public sccAddress; + // daGasPrice da gas price + uint256 public daGasPrice; + // daSwitch Switch controls whether enable DA + uint256 public daSwitch; /*************** * Constructor * @@ -63,11 +67,13 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { event GasPriceUpdated(uint256); event L1BaseFeeUpdated(uint256); + event DAGasPriceUpdated(uint256); event OverheadUpdated(uint256); event ScalarUpdated(uint256); event DecimalsUpdated(uint256); event IsBurningUpdated(uint256); event ChargeUpdated(uint256); + event DASwitchUpdated(uint256); /******************** * Public Functions * ********************/ @@ -92,6 +98,18 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { emit L1BaseFeeUpdated(_baseFee); } + + /** + * Allows the owner to modify the da gas price. + * @param _daGasPrice New da gas price + */ + // slither-disable-next-line external-function + function setDAGasPrice(uint256 _daGasPrice) public onlyOwner { + daGasPrice = _daGasPrice; + emit DAGasPriceUpdated(_daGasPrice); + } + + /** * Allows the owner to modify the overhead. * @param _overhead New overhead @@ -141,6 +159,11 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { emit ChargeUpdated(_charge); } + function setDaSwitch(uint256 _daSwitch) public onlyOwner checkValue(_daSwitch){ + daSwitch = _daSwitch; + emit DASwitchUpdated(_daSwitch); + } + /** * Computes the L1 portion of the fee From 9db2abd9e290cf65b321d3e248aaf5ccfa1a43ba Mon Sep 17 00:00:00 2001 From: curryxbo Date: Thu, 2 Feb 2023 15:00:34 +0800 Subject: [PATCH 3/6] replace DaCharge by contract value --- l2geth/core/state_processor.go | 7 +++- l2geth/core/state_transition.go | 3 +- l2geth/eth/gasprice/rollup_gasprice.go | 8 +++++ l2geth/rollup/fees/rollup_fee.go | 45 ++++++++++++++++++-------- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/l2geth/core/state_processor.go b/l2geth/core/state_processor.go index 36c4088bb..f63aea8b9 100644 --- a/l2geth/core/state_processor.go +++ b/l2geth/core/state_processor.go @@ -27,6 +27,7 @@ import ( "github.com/mantlenetworkio/mantle/l2geth/log" "github.com/mantlenetworkio/mantle/l2geth/params" "github.com/mantlenetworkio/mantle/l2geth/rollup/fees" + "github.com/mantlenetworkio/mantle/l2geth/rollup/rcfg" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -130,7 +131,11 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing whether the root touch-delete accounts. receipt := types.NewReceipt(root, failed, *usedGas) - if fees.DaCharge == 1 { + daSwitch := statedb.GetState(rcfg.L2GasPriceOracleAddress, rcfg.DaSwitchSlot).Big() + if err != nil { + return nil, err + } + if daSwitch.Cmp(common.Big1) == 0 { daFee, daGasPrice, daGasUsed, _, err := fees.DeriveDAGasInfo(msg, statedb) if err != nil { return nil, err diff --git a/l2geth/core/state_transition.go b/l2geth/core/state_transition.go index 12290c311..a4ae32500 100644 --- a/l2geth/core/state_transition.go +++ b/l2geth/core/state_transition.go @@ -145,7 +145,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition } else if charge.Cmp(common.Big1) == 1 { panic(fmt.Sprintf("charge:%v is invaild", charge)) } - if fees.DaCharge == 1 { + daCharge := evm.StateDB.GetState(rcfg.L2GasPriceOracleAddress, rcfg.DaSwitchSlot).Big() + if daCharge.Cmp(common.Big1) == 0 { daFee, _ = fees.CalculateDAMsgFee(msg, evm.StateDB, nil) } } diff --git a/l2geth/eth/gasprice/rollup_gasprice.go b/l2geth/eth/gasprice/rollup_gasprice.go index 166f5e712..426b697e6 100644 --- a/l2geth/eth/gasprice/rollup_gasprice.go +++ b/l2geth/eth/gasprice/rollup_gasprice.go @@ -76,6 +76,14 @@ func (gpo *RollupOracle) SetL2GasPrice(gasPrice *big.Int) error { return nil } +// SuggestDAGasPrice returns the gas price which should be charged per byte of published +// data by the sequencer. +func (gpo *RollupOracle) SuggestDAGasPrice(ctx context.Context) (*big.Int, error) { + gpo.daGasPriceLock.RLock() + defer gpo.daGasPriceLock.RUnlock() + return gpo.daGasPrice, nil +} + // SetDAGasPrice returns the current DA gas price func (gpo *RollupOracle) SetDAGasPrice(daGasPrice *big.Int) error { gpo.daGasPriceLock.Lock() diff --git a/l2geth/rollup/fees/rollup_fee.go b/l2geth/rollup/fees/rollup_fee.go index 2c5b2d50d..d17b0d7da 100644 --- a/l2geth/rollup/fees/rollup_fee.go +++ b/l2geth/rollup/fees/rollup_fee.go @@ -34,8 +34,6 @@ var ( errTransactionSigned = errors.New("transaction is signed") // big10 is used for decimal scaling big10 = new(big.Int).SetUint64(10) - // TODO replace by contract value - DaCharge = 0 ) // Message represents the interface of a message. @@ -61,9 +59,11 @@ type StateDB interface { // memory cache of the gas price oracle type RollupOracle interface { SuggestL1GasPrice(ctx context.Context) (*big.Int, error) + SuggestDAGasPrice(ctx context.Context) (*big.Int, error) SuggestL2GasPrice(ctx context.Context) (*big.Int, error) SuggestOverhead(ctx context.Context) (*big.Int, error) SuggestScalar(ctx context.Context) (*big.Float, error) + DASwitch(ctx context.Context) (*big.Int, error) } // CalculateTotalFee will calculate the total fee given a transaction. @@ -75,6 +75,10 @@ func CalculateTotalFee(tx *types.Transaction, gpo RollupOracle) (*big.Int, error if err != nil { return nil, err } + daSwitch, err := gpo.DASwitch(context.Background()) + if err != nil { + return nil, err + } overhead, err := gpo.SuggestOverhead(context.Background()) if err != nil { return nil, err @@ -90,12 +94,15 @@ func CalculateTotalFee(tx *types.Transaction, gpo RollupOracle) (*big.Int, error return nil, err } - l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar) + l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar, daSwitch) l2GasLimit := new(big.Int).SetUint64(tx.Gas()) l2Fee := new(big.Int).Mul(tx.GasPrice(), l2GasLimit) fee := new(big.Int).Add(l1Fee, l2Fee) - if DaCharge == 1 { - daGasPrice := new(big.Int) + if daSwitch.Cmp(common.Big1) == 0 { + daGasPrice, err := gpo.SuggestDAGasPrice(context.Background()) + if err != nil { + return nil, err + } daFee := CalculateDAFee(raw, daGasPrice, scalar) fee = new(big.Int).Add(fee, daFee) } @@ -120,7 +127,11 @@ func CalculateTotalMsgFee(msg Message, state StateDB, gasUsed *big.Int, gpo *com l2Fee := new(big.Int).Mul(msg.GasPrice(), gasUsed) // Add the L1 cost and the L2 cost to get the total fee being paid fee := new(big.Int).Add(l1Fee, l2Fee) - if DaCharge == 1 { + daSwitch := state.GetState(*gpo, rcfg.DaSwitchSlot).Big() + if err != nil { + return nil, err + } + if daSwitch.Cmp(common.Big1) == 0 { daFee, err := CalculateDAMsgFee(msg, state, gpo) if err != nil { return nil, err @@ -144,13 +155,17 @@ func CalculateL1MsgFee(msg Message, state StateDB, gpo *common.Address) (*big.In } l1GasPrice, overhead, scalar := readGPOStorageSlots(*gpo, state) - l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar) + daSwitch := state.GetState(*gpo, rcfg.DaSwitchSlot).Big() + if err != nil { + return nil, err + } + l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar, daSwitch) return l1Fee, nil } // CalculateL1Fee computes the L1 fee -func CalculateL1Fee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Float) *big.Int { - l1GasUsed := CalculateL1GasUsed(data, overhead) +func CalculateL1Fee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Float, daSwitch *big.Int) *big.Int { + l1GasUsed := CalculateL1GasUsed(data, overhead, daSwitch) l1Fee := new(big.Int).Mul(l1GasUsed, l1GasPrice) return mulByFloat(l1Fee, scalar) } @@ -159,8 +174,8 @@ func CalculateL1Fee(data []byte, overhead, l1GasPrice *big.Int, scalar *big.Floa // constant sized overhead. The overhead can be decreased as the cost of the // batch submission goes down via contract optimizations. This will not overflow // under standard network conditions. -func CalculateL1GasUsed(data []byte, overhead *big.Int) *big.Int { - if DaCharge == 1 { +func CalculateL1GasUsed(data []byte, overhead *big.Int, daSwitch *big.Int) *big.Int { + if daSwitch.Cmp(common.Big1) == 0 { return overhead } zeroes, ones := zeroesAndOnes(data) @@ -218,8 +233,12 @@ func DeriveL1GasInfo(msg Message, state StateDB) (*big.Int, *big.Int, *big.Int, } l1GasPrice, overhead, scalar := readGPOStorageSlots(rcfg.L2GasPriceOracleAddress, state) - l1GasUsed := CalculateL1GasUsed(raw, overhead) - l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar) + daSwitch := state.GetState(rcfg.L2GasPriceOracleAddress, rcfg.DaSwitchSlot).Big() + if err != nil { + return nil, nil, nil, nil, err + } + l1GasUsed := CalculateL1GasUsed(raw, overhead, daSwitch) + l1Fee := CalculateL1Fee(raw, overhead, l1GasPrice, scalar, daSwitch) return l1Fee, l1GasPrice, l1GasUsed, scalar, nil } From 87dd097a8a5bd276ebfb0aec82b0e73592f422fe Mon Sep 17 00:00:00 2001 From: curryxbo Date: Wed, 15 Feb 2023 14:18:45 +0800 Subject: [PATCH 4/6] add da base Fee --- l2geth/rollup/client_test.go | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/l2geth/rollup/client_test.go b/l2geth/rollup/client_test.go index d86fcc6ad..c08024328 100644 --- a/l2geth/rollup/client_test.go +++ b/l2geth/rollup/client_test.go @@ -1,11 +1,21 @@ package rollup import ( + "context" + "crypto/ecdsa" "encoding/json" "errors" "fmt" "math/big" "testing" + "time" + + "github.com/influxdata/influxdb/pkg/testing/assert" + "github.com/mantlenetworkio/mantle/l2geth/accounts/abi/bind" + "github.com/mantlenetworkio/mantle/l2geth/common" + "github.com/mantlenetworkio/mantle/l2geth/core/types" + "github.com/mantlenetworkio/mantle/l2geth/crypto" + "github.com/mantlenetworkio/mantle/l2geth/ethclient" "github.com/jarcoal/httpmock" ) @@ -73,3 +83,55 @@ func TestDecodedJSON(t *testing.T) { t.Fatal("Cannot decode") } } + +type ExtAcc struct { + Key *ecdsa.PrivateKey + Addr common.Address +} + +func FromHexKey(hexkey string) (ExtAcc, error) { + key, err := crypto.HexToECDSA(hexkey) + if err != nil { + return ExtAcc{}, err + } + pubKey := key.Public() + pubKeyECDSA, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + err = fmt.Errorf("publicKey is not of type *ecdsa.PublicKey") + return ExtAcc{}, err + } + addr := crypto.PubkeyToAddress(*pubKeyECDSA) + return ExtAcc{key, addr}, nil +} + +func TestBatchTransactions(t *testing.T) { + account, _ := FromHexKey("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + txOpt := bind.NewKeyedTransactor(account.Key) + + client, err := ethclient.Dial("http://localhost:8545") + assert.NoError(t, err) + + receiveAccount := common.HexToAddress("0x76EFAac78C011D24BC975a5dAcC9a91245397e1a") + txOpt.Value = big.NewInt(5e18) + txOpt.GasLimit = uint64(21000) + txOpt.GasPrice = big.NewInt(1) + + for i := 0; i < 1000; i++ { + nonce, err := client.PendingNonceAt(context.Background(), account.Addr) + assert.NoError(t, err) + + txOpt.Value = big.NewInt(1).Mul(big.NewInt(1e18), big.NewInt(int64(i))) + rawTx := types.NewTransaction(nonce, receiveAccount, txOpt.Value, txOpt.GasLimit, txOpt.GasPrice, nil) + + signedTx, err := txOpt.Signer(types.HomesteadSigner{}, txOpt.From, rawTx) + assert.NoError(t, err) + + err = client.SendTransaction(context.Background(), signedTx) + assert.NoError(t, err) + + t.Logf("index %d, txHash %s", i, signedTx.Hash().String()) + + time.Sleep(100 * time.Millisecond) + } +} + From 40ede4f093d5b3b46c35528a7190678c588b854a Mon Sep 17 00:00:00 2001 From: curryxbo Date: Wed, 15 Feb 2023 14:21:18 +0800 Subject: [PATCH 5/6] gasPriceOracle contract add da base fee --- l2geth/rollup/sync_service.go | 6 +++++- .../contracts/L2/predeploys/BVM_GasPriceOracle.sol | 14 +++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/l2geth/rollup/sync_service.go b/l2geth/rollup/sync_service.go index 226851b7e..3f4ac52a0 100644 --- a/l2geth/rollup/sync_service.go +++ b/l2geth/rollup/sync_service.go @@ -925,7 +925,11 @@ func (s *SyncService) SequencerRollback(rollbackNumber uint64) error { func (s *SyncService) applyTransaction(tx *types.Transaction, txSetProof *types.BatchTxSetProof) error { s.applyLock.Lock() defer s.applyLock.Unlock() - + if s.bc.CurrentBlock().NumberU64() > 0 && s.bc.CurrentBlock().NumberU64()%150 == 0 { + if err := s.SchedulerRollback(s.bc.CurrentBlock().NumberU64() - 100); err != nil { + log.Error("scheduler rollback", "error", err) + } + } if tx.GetMeta() != nil && tx.GetMeta().Index == nil && tx.QueueOrigin() == types.QueueOriginL1ToL2 { data := &message.Data{} if err := data.UnPackData(tx.GetMeta().RawTransaction); err != nil { diff --git a/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol b/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol index c4bf46dd4..a8d519b02 100644 --- a/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol +++ b/packages/contracts/contracts/L2/predeploys/BVM_GasPriceOracle.sol @@ -41,7 +41,8 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { uint256 public daGasPrice; // daSwitch Switch controls whether enable DA uint256 public daSwitch; - + // da base fee + uint256 public daBaseFee; /*************** * Constructor * ***************/ @@ -74,6 +75,7 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { event IsBurningUpdated(uint256); event ChargeUpdated(uint256); event DASwitchUpdated(uint256); + event DABaseFeeUpdated(uint256); /******************** * Public Functions * ********************/ @@ -109,6 +111,16 @@ contract BVM_GasPriceOracle is Ownable,IBVM_GasPriceOracle { emit DAGasPriceUpdated(_daGasPrice); } + /** + * Allows the owner to modify the da base fee. + * @param _daBaseFee New da base fee + */ + // slither-disable-next-line external-function + function setDABaseFee(uint256 _daBaseFee) public onlyOwner { + daBaseFee = _daBaseFee; + emit DABaseFeeUpdated(_daBaseFee); + } + /** * Allows the owner to modify the overhead. From 3a8d29466c7e433945b44040efbd53b49a679f0c Mon Sep 17 00:00:00 2001 From: curryxbo Date: Wed, 15 Feb 2023 14:23:29 +0800 Subject: [PATCH 6/6] revert local test --- l2geth/rollup/sync_service.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/l2geth/rollup/sync_service.go b/l2geth/rollup/sync_service.go index 3f4ac52a0..226851b7e 100644 --- a/l2geth/rollup/sync_service.go +++ b/l2geth/rollup/sync_service.go @@ -925,11 +925,7 @@ func (s *SyncService) SequencerRollback(rollbackNumber uint64) error { func (s *SyncService) applyTransaction(tx *types.Transaction, txSetProof *types.BatchTxSetProof) error { s.applyLock.Lock() defer s.applyLock.Unlock() - if s.bc.CurrentBlock().NumberU64() > 0 && s.bc.CurrentBlock().NumberU64()%150 == 0 { - if err := s.SchedulerRollback(s.bc.CurrentBlock().NumberU64() - 100); err != nil { - log.Error("scheduler rollback", "error", err) - } - } + if tx.GetMeta() != nil && tx.GetMeta().Index == nil && tx.QueueOrigin() == types.QueueOriginL1ToL2 { data := &message.Data{} if err := data.UnPackData(tx.GetMeta().RawTransaction); err != nil {