diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index a9454e311d..f9602bbddf 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -831,6 +831,7 @@ func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPri func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap } func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap } func (m callMsg) FeeCurrency() *common.Address { return m.CallMsg.FeeCurrency } +func (m callMsg) MaxFeeInFeeCurrency() *big.Int { return m.CallMsg.MaxFeeInFeeCurrency } func (m callMsg) GatewayFeeRecipient() *common.Address { return m.CallMsg.GatewayFeeRecipient } func (m callMsg) GatewaySet() bool { return m.CallMsg.GatewayFeeRecipient != nil || (m.CallMsg.GatewayFee != nil && m.CallMsg.GatewayFee.Sign() != 0) diff --git a/accounts/external/backend.go b/accounts/external/backend.go index f73d2aad8e..5cc4d93051 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -223,7 +223,7 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio switch tx.Type() { case types.LegacyTxType, types.AccessListTxType: args.GasPrice = (*hexutil.Big)(tx.GasPrice()) - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap()) default: diff --git a/cmd/mycelo/env_commands.go b/cmd/mycelo/env_commands.go index a469d9aa18..3205b85aa9 100644 --- a/cmd/mycelo/env_commands.go +++ b/cmd/mycelo/env_commands.go @@ -1,6 +1,7 @@ package main import ( + "encoding/json" "fmt" "github.com/celo-org/celo-blockchain/cmd/utils" @@ -22,6 +23,7 @@ var getAccountCommand = cli.Command{ Flags: []cli.Flag{ idxFlag, accountTypeFlag, + jsonFlag, }, } @@ -36,6 +38,10 @@ var ( Usage: `Account type (validator, developer, txNode, faucet, attestation, priceOracle, proxy, attestationBot, votingBot, txNodePrivate, validatorGroup, admin)`, Value: &env.DeveloperAT, } + jsonFlag = cli.BoolFlag{ + Name: "json", + Usage: "output json", + } ) func getAccount(ctx *cli.Context) error { @@ -52,6 +58,28 @@ func getAccount(ctx *cli.Context) error { return err } - fmt.Printf("AccountType: %s\nIndex:%d\nAddress: %s\nPrivateKey: %s\n", accountType, idx, account.Address.Hex(), account.PrivateKeyHex()) + jsonOutput := ctx.Bool(jsonFlag.Name) + + if jsonOutput { + output := struct { + AccountType string `json:"accountType"` + Index int `json:"index"` + Address string `json:"address"` + PrivateKey string `json:"privateKey"` + }{ + AccountType: accountType.String(), + Index: idx, + Address: account.Address.Hex(), + PrivateKey: account.PrivateKeyHex(), + } + + jsonData, err := json.Marshal(output) + if err != nil { + return err + } + fmt.Println(string(jsonData)) + } else { + fmt.Printf("AccountType: %s\nIndex:%d\nAddress: %s\nPrivateKey: %s\n", accountType, idx, account.Address.Hex(), account.PrivateKeyHex()) + } return nil } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 5cf1d561f3..272b68d927 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -521,7 +521,7 @@ var ( } HTTPApiFlag = cli.StringFlag{ Name: "http.api", - Usage: "API's offered over the HTTP-RPC interface", + Usage: "Comma separated list of API's offered over the HTTP-RPC interface choose from admin,debug,eth,istanbul,miner,net,personal,txpool,web3,les,vflux", Value: "", } HTTPPathPrefixFlag = cli.StringFlag{ @@ -574,7 +574,7 @@ var ( } WSApiFlag = cli.StringFlag{ Name: "ws.api", - Usage: "API's offered over the WS-RPC interface", + Usage: "Comma separated list of API's offered over the WS-RPC interface choose from admin,debug,eth,istanbul,miner,net,personal,txpool,web3,les,vflux", Value: "", } WSAllowedOriginsFlag = cli.StringFlag{ diff --git a/common/types.go b/common/types.go index 7192433e36..c2cde9959f 100644 --- a/common/types.go +++ b/common/types.go @@ -442,16 +442,3 @@ func (ma *MixedcaseAddress) ValidChecksum() bool { func (ma *MixedcaseAddress) Original() string { return ma.original } - -func AreSameAddress(a, b *Address) bool { - // both are nil or point to the same address - if a == b { - return true - } - // if only one is nil - if a == nil || b == nil { - return false - } - // if they point to the same - return *a == *b -} diff --git a/contracts/erc20gas/erc20gas.go b/contracts/erc20gas/erc20gas.go index 910baf7fef..34b50af0f1 100644 --- a/contracts/erc20gas/erc20gas.go +++ b/contracts/erc20gas/erc20gas.go @@ -7,6 +7,7 @@ import ( "github.com/celo-org/celo-blockchain/accounts/abi" "github.com/celo-org/celo-blockchain/common" "github.com/celo-org/celo-blockchain/common/hexutil" + "github.com/celo-org/celo-blockchain/contracts/currency" "github.com/celo-org/celo-blockchain/contracts/internal/n" "github.com/celo-org/celo-blockchain/core/types" "github.com/celo-org/celo-blockchain/core/vm" @@ -27,12 +28,17 @@ var ( // Returns nil if debit is possible, used in tx pool validation func TryDebitFees(tx *types.Transaction, from common.Address, currentVMRunner vm.EVMRunner) error { - cost := new(big.Int).SetUint64(tx.Gas()) - cost.Mul(cost, tx.GasFeeCap()) - + var fee *big.Int = tx.Fee() + if tx.Type() == types.CeloDenominatedTxType { + rate, err := currency.GetExchangeRate(currentVMRunner, tx.FeeCurrency()) + if err != nil { + return err + } + fee = rate.FromBase(fee) + } // The following code is similar to DebitFees, but that function does not work on a vm.EVMRunner, // so we have to adapt it instead of reusing. - transactionData := common.GetEncodedAbi(debitGasFeesSelector, [][]byte{common.AddressToAbi(from), common.AmountToAbi(cost)}) + transactionData := common.GetEncodedAbi(debitGasFeesSelector, [][]byte{common.AddressToAbi(from), common.AmountToAbi(fee)}) ret, err := currentVMRunner.ExecuteAndDiscardChanges(*tx.FeeCurrency(), transactionData, maxGasForDebitGasFeesTransactions, common.Big0) if err != nil { diff --git a/core/error.go b/core/error.go index e968ec9ad5..f5515dd858 100644 --- a/core/error.go +++ b/core/error.go @@ -121,4 +121,14 @@ var ( // ErrGatewayFeeDeprecated is returned when a transaction containing a gateway fee is encountered after the // G hardfork ErrGatewayFeeDeprecated = errors.New("gateway fee is deprecated") + + // ErrDenominatedNoMax is returned when a transaction containing a fee currency has no maxFeeInFeeCurrency set. + ErrDenominatedNoMax = errors.New("CELO denominated tx has no maxFeeInFeeCurrency") + + // ErrDenominatedNoCurrency is returned when a celo-denominated transaction has no fee currency set + ErrDenominatedNoCurrency = errors.New("CELO denominated tx has no fee currency") + + // ErrDenominatedLowMaxFee is returned when a celo denominated transaction, with the current exchange rate, + // the MaxFeeInFeeCurrency cannot cover the tx.Fee() + ErrDenominatedLowMaxFee = errors.New("CELO denominated tx MaxFeeInCurrency cannot cover gas fee costs") ) diff --git a/core/state_processor.go b/core/state_processor.go index 089927b866..c0fa3663d5 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -141,6 +141,10 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool return nil, ErrTxTypeNotSupported } + if tx.Type() == types.CeloDenominatedTxType && !config.IsHFork(blockNumber) { + return nil, ErrTxTypeNotSupported + } + // Create a new context to be used in the EVM environment txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) diff --git a/core/state_transition.go b/core/state_transition.go index 041f66e08d..3441ac9b1a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -74,6 +74,7 @@ type StateTransition struct { vmRunner vm.EVMRunner gasPriceMinimum *big.Int sysCtx *SysContractCallCtx + erc20FeeDebited *big.Int } // Message represents a message sent to a contract. @@ -86,10 +87,12 @@ type Message interface { GasTipCap() *big.Int Gas() uint64 - // FeeCurrency specifies the currency for gas and gateway fees. + // FeeCurrency specifies the currency from which to pay for the fees // nil correspond to Celo Gold (native currency). // All other values should correspond to ERC20 contract addresses extended to be compatible with gas payments. FeeCurrency() *common.Address + // MaxFeeInFeeCurrency Set iff it's a celo denominated tx. Maximum value of fees when converted to FeeCurrency. + MaxFeeInFeeCurrency() *big.Int GatewayFeeRecipient() *common.Address GatewayFee() *big.Int GatewaySet() bool @@ -214,7 +217,12 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool, vmRunner vm.EVMRunner, sysCtx *SysContractCallCtx) *StateTransition { var gasPriceMinimum *big.Int if evm.ChainConfig().IsEspresso(evm.Context.BlockNumber) { - gasPriceMinimum = sysCtx.GetGasPriceMinimum(msg.FeeCurrency()) + var feeCurrency *common.Address = msg.FeeCurrency() + if msg.MaxFeeInFeeCurrency() != nil { + // Celo denominated tx + feeCurrency = nil + } + gasPriceMinimum = sysCtx.GetGasPriceMinimum(feeCurrency) } else { gasPriceMinimum, _ = gpm.GetBaseFeeForCurrency(vmRunner, msg.FeeCurrency(), nil) } @@ -256,7 +264,7 @@ func (st *StateTransition) to() common.Address { } // payFees deducts gas and gateway fees from sender balance and adds the purchased amount of gas to the state. -func (st *StateTransition) payFees(espresso bool) error { +func (st *StateTransition) payFees(espresso bool, feeCurrencyRate *currency.ExchangeRate) error { var isWhiteListed bool if espresso { isWhiteListed = st.sysCtx.IsWhitelisted(st.msg.FeeCurrency()) @@ -267,8 +275,7 @@ func (st *StateTransition) payFees(espresso bool) error { log.Trace("Fee currency not whitelisted", "fee currency address", st.msg.FeeCurrency()) return ErrNonWhitelistedFeeCurrency } - - if err := st.canPayFee(st.msg.From(), st.msg.FeeCurrency(), espresso); err != nil { + if err := st.canPayFee(st.msg.From(), st.msg.FeeCurrency(), espresso, feeCurrencyRate); err != nil { return err } if err := st.gp.SubGas(st.msg.Gas()); err != nil { @@ -277,7 +284,7 @@ func (st *StateTransition) payFees(espresso bool) error { st.initialGas = st.msg.Gas() st.gas += st.msg.Gas() - err := st.debitFee(st.msg.From(), st.msg.FeeCurrency()) + err := st.debitFee(st.msg.From(), st.msg.FeeCurrency(), feeCurrencyRate) return err } @@ -290,7 +297,7 @@ func (st *StateTransition) payFees(espresso bool) error { // For non-native tokens(cUSD, cEUR, ...) as feeCurrency: // - Pre-Espresso: it ensures balance > GasPrice * gas + gatewayFee (3) // - Post-Espresso: it ensures balance >= GasFeeCap * gas + gatewayFee (4) -func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *common.Address, espresso bool) error { +func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *common.Address, espresso bool, feeCurrencyRate *currency.ExchangeRate) error { if feeCurrency == nil { balance := st.state.GetBalance(st.msg.From()) if espresso { @@ -323,12 +330,22 @@ func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *c return err } if espresso { + var feeGap *big.Int // feeGap = GasFeeCap * gas + gatewayFee, as in (4) - feeGap := new(big.Int).SetUint64(st.msg.Gas()) + feeGap = new(big.Int).SetUint64(st.msg.Gas()) feeGap.Mul(feeGap, st.gasFeeCap) if st.msg.GatewayFeeRecipient() != nil { feeGap.Add(feeGap, st.msg.GatewayFee()) } + if st.msg.MaxFeeInFeeCurrency() != nil { + // Celo Denominated Tx: max fee is a tx field + // Translate fees to feeCurrency + feeGap = feeCurrencyRate.FromBase(feeGap) + // Check that fee <= MaxFeeInFeeCurrency + if feeGap.Cmp(st.msg.MaxFeeInFeeCurrency()) > 0 { + return ErrDenominatedLowMaxFee + } + } if balance.Cmp(feeGap) < 0 { return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), balance, feeGap) } @@ -346,7 +363,7 @@ func (st *StateTransition) canPayFee(accountOwner common.Address, feeCurrency *c return nil } -func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Address) (err error) { +func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Address, feeCurrencyRate *currency.ExchangeRate) (err error) { if st.evm.Config.SkipDebitCredit { return nil } @@ -361,7 +378,16 @@ func (st *StateTransition) debitFee(from common.Address, feeCurrency *common.Add st.state.SubBalance(from, effectiveFee) return nil } else { - return erc20gas.DebitFees(st.evm, from, effectiveFee, feeCurrency) + var currencyFee *big.Int + if st.msg.MaxFeeInFeeCurrency() == nil { + // Normal feeCurrency tx + currencyFee = effectiveFee + } else { + // Celo denominated tx + currencyFee = feeCurrencyRate.FromBase(effectiveFee) + } + st.erc20FeeDebited = currencyFee + return erc20gas.DebitFees(st.evm, from, currencyFee, feeCurrency) } } @@ -450,6 +476,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { if st.evm.ChainConfig().IsGingerbread(st.evm.Context.BlockNumber) && st.msg.GatewaySet() { return nil, ErrGatewayFeeDeprecated } + if !st.evm.ChainConfig().IsHFork(st.evm.Context.BlockNumber) && st.msg.MaxFeeInFeeCurrency() != nil { + return nil, ErrTxTypeNotSupported + } + if st.msg.FeeCurrency() == nil && st.msg.MaxFeeInFeeCurrency() != nil { + return nil, ErrDenominatedNoCurrency + } + feeCurrencyRate, err := currency.GetExchangeRate(st.vmRunner, st.msg.FeeCurrency()) + if err != nil { + return nil, err + } // Check clauses 1-2 if err := st.preCheck(); err != nil { @@ -481,7 +517,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.msg.Gas(), gas) } // Check clauses 3-4, pay the fees (which buys gas), and subtract the intrinsic gas - err = st.payFees(espresso) + err = st.payFees(espresso, feeCurrencyRate) if err != nil { log.Error("Transaction failed to buy gas", "err", err, "gas", gas) return nil, err @@ -517,7 +553,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { st.refundGas(params.RefundQuotientEIP3529) } - err = st.creditTxFees() + err = st.creditTxFees(feeCurrencyRate) if err != nil { return nil, err } @@ -529,7 +565,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } // creditTxFees calculates the amounts and recipients of transaction fees and credits the accounts. -func (st *StateTransition) creditTxFees() error { +func (st *StateTransition) creditTxFees(feeCurrencyRate *currency.ExchangeRate) error { if st.evm.Config.SkipDebitCredit { return nil } @@ -551,6 +587,23 @@ func (st *StateTransition) creditTxFees() error { // No need to do effectiveTip calculation, because st.gasPrice == effectiveGasPrice, and effectiveTip = effectiveGasPrice - baseTxFee tipTxFee := new(big.Int).Sub(totalTxFee, baseTxFee) + if st.msg.MaxFeeInFeeCurrency() != nil { + // Celo Denominated + + // We want to ensure that + // st.erc20FeeDebited = tipTxFee + baseTxFee + refund + // so that debit and credit totals match. Since the exchange rate + // conversions have limited accuracy, the only way to achieve this + // is to calculate one of the three credit values based on the two + // others after the exchange rate conversion. + tipTxFee = feeCurrencyRate.FromBase(tipTxFee) + baseTxFee = feeCurrencyRate.FromBase(baseTxFee) + totalTxFee.Add(tipTxFee, baseTxFee) + refund.Sub(st.erc20FeeDebited, totalTxFee) // refund = debited - tip - basefee + // No need to exchange gateway fee since it's it's deprecated on G fork, + // and MaxFeeInFeeCurrency can only be present in H fork (which implies G fork) + } + feeCurrency := st.msg.FeeCurrency() gatewayFeeRecipient := st.msg.GatewayFeeRecipient() diff --git a/core/tx_list.go b/core/tx_list.go index 23caa2b9ba..4fa01bd6b3 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -254,11 +254,9 @@ type txList struct { strict bool // Whether nonces are strictly continuous or not txs *txSortedMap // Heap indexed sorted hash map of the transactions - nativecostcap *big.Int // Price of the highest costing transaction paid with native fees (reset only if exceeds balance) - feecaps map[common.Address]*big.Int // Price of the highest costing transaction per fee currency (reset only if exceeds balance) - nativegaspricefloor *big.Int // Lowest gas price minimum in the native currency - gaspricefloors map[common.Address]*big.Int // Lowest gas price minimum per currency (reset only if it is below the gpm) - gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) + nativecostcap *big.Int // Price of the highest costing transaction paid with native fees (reset only if exceeds balance) + feecaps map[common.Address]*big.Int // Price of the highest costing transaction per fee currency (reset only if exceeds balance) + gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) ctx *atomic.Value // transaction pool context } @@ -267,13 +265,11 @@ type txList struct { // gapped, sortable transaction lists. func newTxList(strict bool, ctx *atomic.Value) *txList { return &txList{ - ctx: ctx, - strict: strict, - txs: newTxSortedMap(), - nativecostcap: new(big.Int), - feecaps: make(map[common.Address]*big.Int), - nativegaspricefloor: nil, - gaspricefloors: make(map[common.Address]*big.Int), + ctx: ctx, + strict: strict, + txs: newTxSortedMap(), + nativecostcap: new(big.Int), + feecaps: make(map[common.Address]*big.Int), } } @@ -292,6 +288,17 @@ func (l *txList) FeeCurrencies() []common.Address { return feeCurrencies } +func toCurrency(celoAmount *big.Int, feeCurrency *common.Address, txCtx *txPoolContext) (*big.Int, error) { + if feeCurrency == nil { + return celoAmount, nil + } + currency, err := txCtx.GetCurrency(feeCurrency) + if err != nil { + return nil, err + } + return currency.FromCELO(celoAmount), nil +} + func toCELO(amount *big.Int, feeCurrency *common.Address, txCtx *txPoolContext) (*big.Int, error) { if feeCurrency == nil { return amount, nil @@ -316,7 +323,7 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran var newGasFeeCap, newGasTipCap *big.Int // Short circuit conversion if both are the same currency - if common.AreSameAddress(old.FeeCurrency(), tx.FeeCurrency()) { + if common.AreEqualAddresses(old.DenominatedFeeCurrency(), tx.DenominatedFeeCurrency()) { if old.GasFeeCapCmp(tx) >= 0 || old.GasTipCapCmp(tx) >= 0 { return false, nil } @@ -325,19 +332,19 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran newGasFeeCap = tx.GasFeeCap() newGasTipCap = tx.GasTipCap() } else { + txCtx := l.ctx.Load().(txPoolContext) // Convert old values into tx fee currency var err error - txCtx := l.ctx.Load().(txPoolContext) - if oldGasFeeCap, err = toCELO(old.GasFeeCap(), old.FeeCurrency(), &txCtx); err != nil { + if oldGasFeeCap, err = toCELO(old.GasFeeCap(), old.DenominatedFeeCurrency(), &txCtx); err != nil { return false, nil } - if oldGasTipCap, err = toCELO(old.GasTipCap(), old.FeeCurrency(), &txCtx); err != nil { + if oldGasTipCap, err = toCELO(old.GasTipCap(), old.DenominatedFeeCurrency(), &txCtx); err != nil { return false, nil } - if newGasFeeCap, err = toCELO(tx.GasFeeCap(), tx.FeeCurrency(), &txCtx); err != nil { + if newGasFeeCap, err = toCELO(tx.GasFeeCap(), tx.DenominatedFeeCurrency(), &txCtx); err != nil { return false, nil } - if newGasTipCap, err = toCELO(tx.GasTipCap(), tx.FeeCurrency(), &txCtx); err != nil { + if newGasTipCap, err = toCELO(tx.GasTipCap(), tx.DenominatedFeeCurrency(), &txCtx); err != nil { return false, nil } @@ -366,17 +373,21 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran if cost := tx.Cost(); l.nativecostcap.Cmp(cost) < 0 { l.nativecostcap = cost } - if gasPrice := tx.GasPrice(); l.nativegaspricefloor == nil || l.nativegaspricefloor.Cmp(gasPrice) > 0 { - l.nativegaspricefloor = gasPrice - } } else { - fee := tx.Fee() + var fee *big.Int = tx.Fee() + if tx.Type() == types.CeloDenominatedTxType { + txCtx := l.ctx.Load().(txPoolContext) + var err error + fee, err = toCurrency(fee, feeCurrency, &txCtx) + if err != nil { + log.Error("Can't get rate for currency: ", "currency", feeCurrency.Hex(), "err", err) + // Can't get rate, don't accept tx + return false, nil + } + } if oldFee, ok := l.feecaps[*feeCurrency]; !ok || oldFee.Cmp(fee) < 0 { l.feecaps[*feeCurrency] = fee } - if gasFloor, ok := l.gaspricefloors[*feeCurrency]; !ok || gasFloor.Cmp(tx.GasPrice()) > 0 { - l.gaspricefloors[*feeCurrency] = tx.GasPrice() - } if value := tx.Value(); l.nativecostcap.Cmp(value) < 0 { l.nativecostcap = value } @@ -436,16 +447,30 @@ func (l *txList) Filter(nativeCostLimit *big.Int, feeLimits map[common.Address]* return tx.Cost().Cmp(nativeCostLimit) > 0 || tx.Gas() > gasLimit || txCtx.celoGasPriceMinimumFloor.Cmp(tx.GasPrice()) > 0 } else { feeLimit := feeLimits[*feeCurrency] - fee := tx.Fee() + var fee *big.Int = tx.Fee() log.Trace("Transaction Filter", "hash", tx.Hash(), "Fee currency", tx.FeeCurrency(), "Value", tx.Value(), "Cost Limit", feeLimit, "Gas", tx.Gas(), "Gas Limit", gasLimit) + if tx.Type() == types.CeloDenominatedTxType { + var err error + fee, err = toCurrency(fee, feeCurrency, &txCtx) + if err != nil { + log.Error("Can't get rate for currency: ", "currency", feeCurrency.Hex(), "err", err) + // Can't get rate, remove tx + return true + } + // Celo denominated tx fee is over maxFeeInFeeCurrency + if fee.Cmp(tx.MaxFeeInFeeCurrency()) > 0 { + return true + } + } + // If any of the following is true, the transaction is invalid // The fees are greater than or equal to the balance in the currency return fee.Cmp(feeLimit) >= 0 || // The value of the tx is greater than the native balance of the account tx.Value().Cmp(nativeCostLimit) > 0 || // The gas price is smaller that the gasPriceMinimumFloor - txCtx.CmpValues(txCtx.celoGasPriceMinimumFloor, nil, tx.GasPrice(), tx.FeeCurrency()) > 0 || + txCtx.CmpValues(txCtx.celoGasPriceMinimumFloor, nil, tx.GasPrice(), tx.DenominatedFeeCurrency()) > 0 || // The gas used is greater than the gas limit tx.Gas() > gasLimit } diff --git a/core/tx_multicurrency_priceheap.go b/core/tx_multicurrency_priceheap.go index 5a809179c7..9bb3e89f11 100644 --- a/core/tx_multicurrency_priceheap.go +++ b/core/tx_multicurrency_priceheap.go @@ -73,7 +73,7 @@ func newMultiCurrencyPriceHeap(currencyCmp CurrencyCmpFn, gpm GasPriceMinimums) // if it's not available in the currencyHeaps func (h *multiCurrencyPriceHeap) getHeapFor(tx *types.Transaction) *priceHeap { fc := tx.FeeCurrency() - if fc == nil { + if fc == nil || tx.Type() == types.CeloDenominatedTxType { return h.nativeCurrencyHeap } if _, ok := h.currencyHeaps[*fc]; !ok { diff --git a/core/tx_pool.go b/core/tx_pool.go index e39491fa5f..a2df0ec9dc 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -279,6 +279,7 @@ type TxPool struct { espresso bool // Fork indicator for the Espresso fork. gingerbread bool // Fork indicator for the Gingerbread fork. gingerbreadP2 bool // Fork indicator for the Gingerbread P2 fork. + hfork bool // Fork indicator for the HFork. currentState *state.StateDB // Current state in the blockchain head currentVMRunner vm.EVMRunner // Current EVMRunner @@ -679,6 +680,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if !pool.gingerbreadP2 && tx.Type() == types.CeloDynamicFeeTxV2Type { return ErrTxTypeNotSupported } + // Reject celo denominated fee until h fork + if !pool.hfork && tx.Type() == types.CeloDenominatedTxType { + return ErrTxTypeNotSupported + } // Reject transactions over defined size to prevent DOS attacks if uint64(tx.Size()) > txMaxSize { return ErrOversizedData @@ -715,8 +720,22 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrNonWhitelistedFeeCurrency } + // Celo denominated checks + if tx.Type() == types.CeloDenominatedTxType { + if tx.FeeCurrency() == nil { + return ErrDenominatedNoCurrency + } + if tx.MaxFeeInFeeCurrency() == nil { + return ErrDenominatedNoMax + } + // Celo denominated tx fee is over maxFeeInFeeCurrency + if pool.ctx().CmpValues(tx.Fee(), nil, tx.MaxFeeInFeeCurrency(), tx.FeeCurrency()) > 0 { + return ErrDenominatedLowMaxFee + } + } + // Drop non-local transactions under our own minimal accepted gas price or tip - if !local && pool.ctx().CmpValues(tx.GasTipCap(), tx.FeeCurrency(), pool.gasPrice, nil) < 0 { + if !local && pool.ctx().CmpValues(tx.GasTipCap(), tx.DenominatedFeeCurrency(), pool.gasPrice, nil) < 0 { return ErrUnderpriced } // Ensure the transaction adheres to nonce ordering @@ -741,7 +760,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } ctx := pool.currentCtx.Load().(txPoolContext) - if ctx.CmpValues(ctx.celoGasPriceMinimumFloor, nil, tx.GasPrice(), tx.FeeCurrency()) > 0 { + if ctx.CmpValues(ctx.celoGasPriceMinimumFloor, nil, tx.GasPrice(), tx.DenominatedFeeCurrency()) > 0 { log.Debug("gasPrice less than the minimum floor", "gasPrice", tx.GasPrice(), "feeCurrency", tx.FeeCurrency(), "gasPriceMinimumFloor (Celo)", ctx.celoGasPriceMinimumFloor) return ErrGasPriceDoesNotExceedMinimumFloor } @@ -1425,6 +1444,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) { pool.espresso = pool.chainconfig.IsEspresso(next) pool.gingerbread = pool.chainconfig.IsGingerbread(next) pool.gingerbreadP2 = pool.chainconfig.IsGingerbreadP2(next) + pool.hfork = pool.chainconfig.IsHFork(next) } // promoteExecutables moves transactions that have become processable from the @@ -1729,9 +1749,7 @@ func ValidateTransactorBalanceCoversTx(tx *types.Transaction, from common.Addres balance := currentState.GetBalance(from) // cost = GasFeeCap * gas + value - cost := new(big.Int).SetUint64(tx.Gas()) - cost.Mul(cost, tx.GasFeeCap()) - cost.Add(cost, tx.Value()) + cost := tx.Cost() if balance.Cmp(cost) < 0 { log.Debug("ValidateTransactorBalanceCoversTx: insufficient CELO funds", @@ -1996,7 +2014,7 @@ func (t *txLookup) RemoteToLocals(locals *accountSet) int { func (t *txLookup) RemotesBelowTip(threshold *big.Int, txCtx *txPoolContext) types.Transactions { found := make(types.Transactions, 0, 128) t.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool { - curr, _ := txCtx.GetCurrency(tx.FeeCurrency()) + curr, _ := txCtx.GetCurrency(tx.DenominatedFeeCurrency()) if tx.GasTipCapIntCmp(curr.FromCELO(threshold)) < 0 { found = append(found, tx) } diff --git a/core/types/access_list_tx.go b/core/types/access_list_tx.go index 1abb995b49..0474219f10 100644 --- a/core/types/access_list_tx.go +++ b/core/types/access_list_tx.go @@ -119,3 +119,4 @@ func (tx *AccessListTx) feeCurrency() *common.Address { return nil } func (tx *AccessListTx) gatewayFeeRecipient() *common.Address { return nil } func (tx *AccessListTx) gatewayFee() *big.Int { return nil } func (tx *AccessListTx) ethCompatible() bool { return false } +func (tx *AccessListTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/celo_denominated_tx.go b/core/types/celo_denominated_tx.go new file mode 100644 index 0000000000..140e7b8b65 --- /dev/null +++ b/core/types/celo_denominated_tx.go @@ -0,0 +1,102 @@ +package types + +import ( + "errors" + "math/big" + + "github.com/celo-org/celo-blockchain/common" +) + +var ( + ErrNonCeloDenominated error = errors.New("Tx not CeloDenominated") +) + +type CeloDenominatedTx struct { + ChainID *big.Int + Nonce uint64 + GasTipCap *big.Int + GasFeeCap *big.Int + Gas uint64 + FeeCurrency *common.Address `rlp:"nil"` // nil means native currency + To *common.Address `rlp:"nil"` // nil means contract creation + Value *big.Int + Data []byte + AccessList AccessList + MaxFeeInFeeCurrency *big.Int + + // Signature values + V *big.Int `json:"v" gencodec:"required"` + R *big.Int `json:"r" gencodec:"required"` + S *big.Int `json:"s" gencodec:"required"` +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx *CeloDenominatedTx) copy() TxData { + cpy := &CeloDenominatedTx{ + Nonce: tx.Nonce, + To: copyAddressPtr(tx.To), + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + FeeCurrency: copyAddressPtr(tx.FeeCurrency), + // These are copied below. + AccessList: make(AccessList, len(tx.AccessList)), + Value: new(big.Int), + ChainID: new(big.Int), + GasTipCap: new(big.Int), + GasFeeCap: new(big.Int), + V: new(big.Int), + R: new(big.Int), + S: new(big.Int), + } + copy(cpy.AccessList, tx.AccessList) + if tx.Value != nil { + cpy.Value.Set(tx.Value) + } + if tx.ChainID != nil { + cpy.ChainID.Set(tx.ChainID) + } + if tx.GasTipCap != nil { + cpy.GasTipCap.Set(tx.GasTipCap) + } + if tx.GasFeeCap != nil { + cpy.GasFeeCap.Set(tx.GasFeeCap) + } + if tx.V != nil { + cpy.V.Set(tx.V) + } + if tx.R != nil { + cpy.R.Set(tx.R) + } + if tx.S != nil { + cpy.S.Set(tx.S) + } + return cpy +} + +// accessors for innerTx. +func (tx *CeloDenominatedTx) txType() byte { return CeloDenominatedTxType } +func (tx *CeloDenominatedTx) chainID() *big.Int { return tx.ChainID } +func (tx *CeloDenominatedTx) protected() bool { return true } +func (tx *CeloDenominatedTx) accessList() AccessList { return tx.AccessList } +func (tx *CeloDenominatedTx) data() []byte { return tx.Data } +func (tx *CeloDenominatedTx) gas() uint64 { return tx.Gas } +func (tx *CeloDenominatedTx) gasFeeCap() *big.Int { return tx.GasFeeCap } +func (tx *CeloDenominatedTx) gasTipCap() *big.Int { return tx.GasTipCap } +func (tx *CeloDenominatedTx) gasPrice() *big.Int { return tx.GasFeeCap } +func (tx *CeloDenominatedTx) value() *big.Int { return tx.Value } +func (tx *CeloDenominatedTx) nonce() uint64 { return tx.Nonce } +func (tx *CeloDenominatedTx) to() *common.Address { return tx.To } + +func (tx *CeloDenominatedTx) rawSignatureValues() (v, r, s *big.Int) { + return tx.V, tx.R, tx.S +} + +func (tx *CeloDenominatedTx) setSignatureValues(chainID, v, r, s *big.Int) { + tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s +} + +func (tx *CeloDenominatedTx) feeCurrency() *common.Address { return tx.FeeCurrency } +func (tx *CeloDenominatedTx) gatewayFeeRecipient() *common.Address { return nil } +func (tx *CeloDenominatedTx) gatewayFee() *big.Int { return nil } +func (tx *CeloDenominatedTx) ethCompatible() bool { return false } +func (tx *CeloDenominatedTx) maxFeeInFeeCurrency() *big.Int { return tx.MaxFeeInFeeCurrency } diff --git a/core/types/celo_dynamic_fee_tx.go b/core/types/celo_dynamic_fee_tx.go index bd9c572c20..0c0fda4e82 100644 --- a/core/types/celo_dynamic_fee_tx.go +++ b/core/types/celo_dynamic_fee_tx.go @@ -116,3 +116,4 @@ func (tx *CeloDynamicFeeTx) feeCurrency() *common.Address { return tx.Fe func (tx *CeloDynamicFeeTx) gatewayFeeRecipient() *common.Address { return tx.GatewayFeeRecipient } func (tx *CeloDynamicFeeTx) gatewayFee() *big.Int { return tx.GatewayFee } func (tx *CeloDynamicFeeTx) ethCompatible() bool { return false } +func (tx *CeloDynamicFeeTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/celo_dynamic_fee_tx_v2.go b/core/types/celo_dynamic_fee_tx_v2.go index bf46f9f7c0..40bbfb7b30 100644 --- a/core/types/celo_dynamic_fee_tx_v2.go +++ b/core/types/celo_dynamic_fee_tx_v2.go @@ -94,3 +94,4 @@ func (tx *CeloDynamicFeeTxV2) feeCurrency() *common.Address { return tx. func (tx *CeloDynamicFeeTxV2) gatewayFeeRecipient() *common.Address { return nil } func (tx *CeloDynamicFeeTxV2) gatewayFee() *big.Int { return nil } func (tx *CeloDynamicFeeTxV2) ethCompatible() bool { return false } +func (tx *CeloDynamicFeeTxV2) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/dynamic_fee_tx.go b/core/types/dynamic_fee_tx.go index 410e42055a..48067005eb 100644 --- a/core/types/dynamic_fee_tx.go +++ b/core/types/dynamic_fee_tx.go @@ -107,3 +107,4 @@ func (tx *DynamicFeeTx) feeCurrency() *common.Address { return nil } func (tx *DynamicFeeTx) gatewayFeeRecipient() *common.Address { return nil } func (tx *DynamicFeeTx) gatewayFee() *big.Int { return nil } func (tx *DynamicFeeTx) ethCompatible() bool { return false } +func (tx *DynamicFeeTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/legacy_tx.go b/core/types/legacy_tx.go index a4ebcf428a..f477830304 100644 --- a/core/types/legacy_tx.go +++ b/core/types/legacy_tx.go @@ -174,3 +174,4 @@ func (tx *LegacyTx) feeCurrency() *common.Address { return tx.FeeCurrenc func (tx *LegacyTx) gatewayFeeRecipient() *common.Address { return tx.GatewayFeeRecipient } func (tx *LegacyTx) gatewayFee() *big.Int { return tx.GatewayFee } func (tx *LegacyTx) ethCompatible() bool { return tx.EthCompatible } +func (tx *LegacyTx) maxFeeInFeeCurrency() *big.Int { return nil } diff --git a/core/types/receipt.go b/core/types/receipt.go index 0636ae7746..2560e1fb89 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -176,7 +176,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { return errEmptyTypedReceipt } r.Type = b[0] - if r.Type == AccessListTxType || r.Type == DynamicFeeTxType || r.Type == CeloDynamicFeeTxType || r.Type == CeloDynamicFeeTxV2Type { + if r.Type == AccessListTxType || r.Type == DynamicFeeTxType || r.Type == CeloDynamicFeeTxType || r.Type == CeloDynamicFeeTxV2Type || r.Type == CeloDenominatedTxType { var dec receiptRLP if err := rlp.DecodeBytes(b[1:], &dec); err != nil { return err @@ -352,6 +352,9 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { case CeloDynamicFeeTxV2Type: w.WriteByte(CeloDynamicFeeTxV2Type) rlp.Encode(w, data) + case CeloDenominatedTxType: + w.WriteByte(CeloDenominatedTxType) + rlp.Encode(w, data) default: // For unsupported types, write nothing. Since this is for // DeriveSha, the error will be caught matching the derived hash diff --git a/core/types/transaction.go b/core/types/transaction.go index a3ceecf5ff..ebec066f06 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -55,6 +55,7 @@ const ( DynamicFeeTxType = 0x02 CeloDynamicFeeTxType = 0x7c // Counting down CeloDynamicFeeTxV2Type = 0x7b + CeloDenominatedTxType = 0x7a ) // Transaction is an Ethereum transaction. @@ -100,8 +101,9 @@ type TxData interface { feeCurrency() *common.Address gatewayFeeRecipient() *common.Address gatewayFee() *big.Int - // Whether this is an ethereum-compatible transaction (i.e. with FeeCurrency, GatewayFeeRecipient and GatewayFee omitted) + // Whether this is an ethereum-compatible transaction (i.e. with FeeCurrency, MaxFeeInFeeCurrency, GatewayFeeRecipient and GatewayFee omitted) ethCompatible() bool + maxFeeInFeeCurrency() *big.Int } // EncodeRLP implements rlp.Encoder @@ -212,6 +214,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { var inner CeloDynamicFeeTxV2 err := rlp.DecodeBytes(b[1:], &inner) return &inner, err + case CeloDenominatedTxType: + var inner CeloDenominatedTx + err := rlp.DecodeBytes(b[1:], &inner) + return &inner, err default: return nil, ErrTxTypeNotSupported } @@ -480,6 +486,9 @@ func (tx *Transaction) GatewaySet() bool { // EthCompatible returns true iff the RLP form of the LegacyTx does not have the celo specific fields. func (tx *Transaction) EthCompatible() bool { return tx.inner.ethCompatible() } +// MaxFeeInFeeCurrency returns the max fee in the fee_currency for celo denominated txs. +func (tx *Transaction) MaxFeeInFeeCurrency() *big.Int { return tx.inner.maxFeeInFeeCurrency() } + // Fee calculates the fess paid by the transaction include the gateway fee. func (tx *Transaction) Fee() *big.Int { return Fee(tx.inner.gasPrice(), tx.inner.gas(), tx.GatewayFee()) @@ -493,12 +502,24 @@ func Fee(gasPrice *big.Int, gasLimit uint64, gatewayFee *big.Int) *big.Int { // CheckEthCompatibility checks that the Celo-only fields are nil-or-0 if EthCompatible is true func (tx *Transaction) CheckEthCompatibility() error { - if tx.EthCompatible() && !(tx.FeeCurrency() == nil && tx.GatewayFeeRecipient() == nil && tx.GatewayFee().Sign() == 0) { + if tx.EthCompatible() && + !(tx.FeeCurrency() == nil && tx.GatewayFeeRecipient() == nil && tx.GatewayFee().Sign() == 0 && tx.MaxFeeInFeeCurrency() == nil) { return ErrEthCompatibleTransactionIsntCompatible } return nil } +// DenominatedFeeCurrency returns in which currency the fields GasPrice, GasTipCap, GasFeeCap, etc are +// denominated in +func (tx *Transaction) DenominatedFeeCurrency() *common.Address { + // not declaring this method in TxData since it's a specific for just one type, + // to avoid cluttering it with more methods. + if tx.Type() == CeloDenominatedTxType { + return nil + } + return tx.FeeCurrency() +} + // Transactions implements DerivableList for transactions. type Transactions []*Transaction @@ -682,6 +703,7 @@ type Message struct { gasFeeCap *big.Int gasTipCap *big.Int feeCurrency *common.Address + maxFeeInFeeCurrency *big.Int gatewayFeeRecipient *common.Address gatewayFee *big.Int data []byte @@ -692,7 +714,7 @@ type Message struct { func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, - feeCurrency, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, + feeCurrency *common.Address, maxFeeInFeeCurrency *big.Int, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, data []byte, accessList AccessList, ethCompatible, isFake bool) Message { m := Message{ from: from, @@ -709,6 +731,7 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b // Celo specific fields feeCurrency: feeCurrency, + maxFeeInFeeCurrency: maxFeeInFeeCurrency, gatewayFeeRecipient: gatewayFeeRecipient, gatewayFee: gatewayFee, ethCompatible: ethCompatible, @@ -735,6 +758,7 @@ func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) { // Celo specific fields feeCurrency: tx.FeeCurrency(), + maxFeeInFeeCurrency: tx.MaxFeeInFeeCurrency(), gatewayFeeRecipient: tx.GatewayFeeRecipient(), gatewayFee: new(big.Int), ethCompatible: tx.EthCompatible(), @@ -770,6 +794,7 @@ func (m Message) Fee() *big.Int { func (m Message) EthCompatible() bool { return m.ethCompatible } func (m Message) FeeCurrency() *common.Address { return m.feeCurrency } +func (m Message) MaxFeeInFeeCurrency() *big.Int { return m.maxFeeInFeeCurrency } func (m Message) GatewayFeeRecipient() *common.Address { return m.gatewayFeeRecipient } func (m Message) GatewayFee() *big.Int { return m.gatewayFee } func (m Message) GatewaySet() bool { diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 29efecbd5d..473b73329c 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -46,6 +46,7 @@ type txJSON struct { FeeCurrency *common.Address `json:"feeCurrency"` // nil means native currency GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient"` // nil means no gateway fee is paid GatewayFee *hexutil.Big `json:"gatewayFee"` + MaxFeeInFeeCurrency *hexutil.Big `json:"maxFeeInFeeCurrency"` // max fee for CELO denominated txs // Access list transaction fields: ChainID *hexutil.Big `json:"chainId,omitempty"` @@ -136,6 +137,21 @@ func (t *Transaction) MarshalJSON() ([]byte, error) { enc.V = (*hexutil.Big)(tx.V) enc.R = (*hexutil.Big)(tx.R) enc.S = (*hexutil.Big)(tx.S) + case *CeloDenominatedTx: + enc.ChainID = (*hexutil.Big)(tx.ChainID) + enc.AccessList = &tx.AccessList + enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) + enc.Gas = (*hexutil.Uint64)(&tx.Gas) + enc.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap) + enc.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap) + enc.FeeCurrency = t.FeeCurrency() + enc.MaxFeeInFeeCurrency = (*hexutil.Big)(tx.MaxFeeInFeeCurrency) + enc.Value = (*hexutil.Big)(tx.Value) + enc.Data = (*hexutil.Bytes)(&tx.Data) + enc.To = t.To() + enc.V = (*hexutil.Big)(tx.V) + enc.R = (*hexutil.Big)(tx.R) + enc.S = (*hexutil.Big)(tx.S) } return json.Marshal(&enc) } @@ -431,7 +447,67 @@ func (t *Transaction) UnmarshalJSON(input []byte) error { return err } } - + case CeloDenominatedTxType: + var itx CeloDenominatedTx + inner = &itx + // Access list is optional for now. + if dec.AccessList != nil { + itx.AccessList = *dec.AccessList + } + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' in transaction") + } + itx.ChainID = (*big.Int)(dec.ChainID) + if dec.To != nil { + itx.To = dec.To + } + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' in transaction") + } + itx.Nonce = uint64(*dec.Nonce) + if dec.MaxPriorityFeePerGas == nil { + return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") + } + itx.GasTipCap = (*big.Int)(dec.MaxPriorityFeePerGas) + if dec.MaxFeePerGas == nil { + return errors.New("missing required field 'maxFeePerGas' for txdata") + } + itx.GasFeeCap = (*big.Int)(dec.MaxFeePerGas) + if dec.Gas == nil { + return errors.New("missing required field 'gas' for txdata") + } + itx.Gas = uint64(*dec.Gas) + itx.FeeCurrency = dec.FeeCurrency + if dec.MaxFeeInFeeCurrency == nil { + return errors.New("missing required field 'maxFeeInFeeCurrency' in transaction") + } + itx.MaxFeeInFeeCurrency = (*big.Int)(dec.MaxFeeInFeeCurrency) + if dec.Value == nil { + return errors.New("missing required field 'value' in transaction") + } + itx.Value = (*big.Int)(dec.Value) + if dec.Data == nil { + return errors.New("missing required field 'input' in transaction") + } + itx.Data = *dec.Data + if dec.V == nil { + return errors.New("missing required field 'v' in transaction") + } + itx.V = (*big.Int)(dec.V) + if dec.R == nil { + return errors.New("missing required field 'r' in transaction") + } + itx.R = (*big.Int)(dec.R) + if dec.S == nil { + return errors.New("missing required field 's' in transaction") + } + itx.S = (*big.Int)(dec.S) + withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 + if withSignature { + if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { + return err + } + } default: return ErrTxTypeNotSupported } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index a118158f5a..30151578cf 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -170,6 +170,78 @@ type Signer interface { Equal(Signer) bool } +type hforkSigner struct{ gingerbreadSigner } + +// NewHForkSigner returns a signer that accepts +// - CIP-66 celo denominated fee transactions +// - CIP-64 celo dynamic fee transactions v2 +// - CIP-42 celo dynamic fee transactions +// - EIP-1559 dynamic fee transactions +// - EIP-2930 access list transactions, +// - EIP-155 replay protected transactions, and +// - legacy Homestead transactions. +func NewHForkSigner(chainId *big.Int) Signer { + return hforkSigner{gingerbreadSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}}} +} + +func (s hforkSigner) Sender(tx *Transaction) (common.Address, error) { + if tx.Type() != CeloDenominatedTxType { + return s.gingerbreadSigner.Sender(tx) + } + V, R, S := tx.RawSignatureValues() + // DynamicFee txs are defined to use 0 and 1 as their recovery + // id, add 27 to become equivalent to unprotected Homestead signatures. + V = new(big.Int).Add(V, big.NewInt(27)) + if tx.ChainId().Cmp(s.chainId) != 0 { + return common.Address{}, ErrInvalidChainId + } + return recoverPlain(s.Hash(tx), R, S, V, true) +} + +func (s hforkSigner) Equal(s2 Signer) bool { + x, ok := s2.(hforkSigner) + return ok && x.chainId.Cmp(s.chainId) == 0 +} + +func (s hforkSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { + txdata, ok := tx.inner.(*CeloDenominatedTx) + if !ok { + return s.gingerbreadSigner.SignatureValues(tx, sig) + } + // Check that chain ID of tx matches the signer. We also accept ID zero here, + // because it indicates that the chain ID was not specified in the tx. + if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { + return nil, nil, nil, ErrInvalidChainId + } + R, S, _ = decodeSignature(sig) + V = big.NewInt(int64(sig[64])) + return R, S, V, nil +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s hforkSigner) Hash(tx *Transaction) common.Hash { + if tx.Type() == CeloDenominatedTxType { + return prefixedRlpHash( + tx.Type(), + []interface{}{ + s.chainId, + tx.Nonce(), + tx.GasTipCap(), + tx.GasFeeCap(), + tx.Gas(), + tx.To(), + tx.Value(), + tx.Data(), + tx.AccessList(), + tx.FeeCurrency(), + tx.MaxFeeInFeeCurrency(), + }) + } + return s.gingerbreadSigner.Hash(tx) + +} + type gingerbreadSigner struct{ londonSigner } // NewGingerbreadSigner returns a signer that accepts diff --git a/e2e_test/e2e_test.go b/e2e_test/e2e_test.go index 573431065e..fc73486ec6 100644 --- a/e2e_test/e2e_test.go +++ b/e2e_test/e2e_test.go @@ -881,3 +881,37 @@ func TestSettingGingerbreadOnGenesisBlock(t *testing.T) { require.Greater(t, block.BaseFee().Uint64(), uint64(0)) require.Greater(t, block.GasLimit(), uint64(0)) } + +// This test checks that retreiveing the "finalized" block results in the same response as retrieving the "latest" block. +func TestGetFinalizedBlock(t *testing.T) { + ac := test.AccountConfig(2, 2) + gingerbreadBlock := common.Big0 + gc, ec, err := test.BuildConfig(ac, gingerbreadBlock) + require.NoError(t, err) + network, shutdown, err := test.NewNetwork(ac, gc, ec) + require.NoError(t, err) + defer shutdown() + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + + // Wait for at least one block to be built. + err = network.AwaitBlock(ctx, 1) + require.NoError(t, err) + + // Stop one of the two validators, so no more blocks can be created. + err = network[1].Close() + require.NoError(t, err) + + c := network[0].WsClient.GetRPCClient() + h := types.Header{} + err = c.CallContext(ctx, &h, "eth_getHeaderByNumber", "latest") + require.NoError(t, err) + require.GreaterOrEqual(t, h.Number.Uint64(), uint64(1)) + + h2 := types.Header{} + err = c.CallContext(ctx, &h2, "eth_getHeaderByNumber", "finalized") + require.NoError(t, err) + + // Check latest and finalzed block are the same + require.Equal(t, h.Hash(), h2.Hash()) +} diff --git a/e2e_test/e2e_transfer_test.go b/e2e_test/e2e_transfer_test.go index 87129b93e2..4ebbbf929f 100644 --- a/e2e_test/e2e_transfer_test.go +++ b/e2e_test/e2e_transfer_test.go @@ -112,30 +112,6 @@ func TestTransferCELO(t *testing.T) { }, expectedErr: nil, }, - { - name: "CeloDynamicFeeTxType - gas = MaxFeePerGas - BaseFee", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - GatewayFee: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo / 10)), - GatewayFeeRecipient: &gateWayFeeRecipient.Address, - }, - expectedErr: core.ErrGatewayFeeDeprecated, - }, - { - name: "CeloDynamicFeeTxType - MaxPriorityFeePerGas", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum), - GatewayFee: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo / 10)), - GatewayFeeRecipient: &gateWayFeeRecipient.Address, - }, - expectedErr: core.ErrGatewayFeeDeprecated, - }, { name: "CeloDynamicFeeTxV2Type - gas = MaxFeePerGas - BaseFee", txArgs: ðapi.TransactionArgs{ @@ -174,7 +150,7 @@ func TestTransferCELO(t *testing.T) { blockNum, err := client.BlockNumber(ctx) require.NoError(t, err) signer := types.MakeSigner(devAccounts[0].ChainConfig, new(big.Int).SetUint64(blockNum)) - tx, err := prepareTransaction(*tc.txArgs, sender.Key, sender.Address, signer, client, true) + tx, err := prepareTransaction(*tc.txArgs, sender.Key, sender.Address, signer, client) require.NoError(t, err) err = client.SendTransaction(ctx, tx) if tc.expectedErr != nil { @@ -249,177 +225,8 @@ func TestTransferCELO(t *testing.T) { } } -// TestTransferCELO checks following accounts: -// - Sender account has transfer value, transaction fee deducted -// - Receiver account has transfer value added. -// - Governance account has base fee added. -// - validator account has tip fee added. -func TestTransferCELOPreGingerbread(t *testing.T) { - ac := test.AccountConfig(1, 3) - var gingerbreadBlock *big.Int = nil - gc, ec, err := test.BuildConfig(ac, gingerbreadBlock) - - require.NoError(t, err) - network, shutdown, err := test.NewNetwork(ac, gc, ec) - require.NoError(t, err) - defer shutdown() - ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) - defer cancel() - - node := network[0] // validator node - client := node.WsClient - devAccounts := test.Accounts(ac.DeveloperAccounts(), gc.ChainConfig()) - sender := devAccounts[0] - recipient := devAccounts[1] - gateWayFeeRecipient := devAccounts[2] - - // Get datum to set GasPrice/MaxFeePerGas/MaxPriorityFeePerGas to sensible values - header, err := network[0].WsClient.HeaderByNumber(ctx, nil) - require.NoError(t, err) - datum, err := network[0].Eth.APIBackend.GasPriceMinimumForHeader(ctx, nil, header) - require.NoError(t, err) - - testCases := []struct { - name string - txArgs *ethapi.TransactionArgs - }{ - { - name: "eth compatible LegacyTxType", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - GasPrice: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - }, - }, - { - name: "eth incompatible LegacyTxType", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - GasPrice: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - GatewayFee: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo / 10)), - GatewayFeeRecipient: &gateWayFeeRecipient.Address, - }, - }, - { - name: "AccessListTxType", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - GasPrice: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - AccessList: &types.AccessList{}, - }, - }, - { - name: "DynamicFeeTxType - tip = MaxFeePerGas - BaseFee", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - }, - }, - { - name: "DynamicFeeTxType - tip = MaxPriorityFeePerGas", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum), - }, - }, - { - name: "CeloDynamicFeeTxType - gas = MaxFeePerGas - BaseFee", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - GatewayFee: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo / 10)), - GatewayFeeRecipient: &gateWayFeeRecipient.Address, - }, - }, - { - name: "CeloDynamicFeeTxType - MaxPriorityFeePerGas", - txArgs: ðapi.TransactionArgs{ - To: &recipient.Address, - Value: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo)), - MaxFeePerGas: (*hexutil.Big)(datum.Mul(datum, new(big.Int).SetInt64(4))), - MaxPriorityFeePerGas: (*hexutil.Big)(datum), - GatewayFee: (*hexutil.Big)(new(big.Int).SetInt64(oneCelo / 10)), - GatewayFeeRecipient: &gateWayFeeRecipient.Address, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - watcher := test.NewBalanceWatcher(client, []common.Address{sender.Address, recipient.Address, gateWayFeeRecipient.Address, node.Address}) - blockNum, err := client.BlockNumber(ctx) - require.NoError(t, err) - signer := types.MakeSigner(devAccounts[0].ChainConfig, new(big.Int).SetUint64(blockNum)) - tx, err := prepareTransaction(*tc.txArgs, sender.Key, sender.Address, signer, client, false) - require.NoError(t, err) - err = client.SendTransaction(ctx, tx) - require.NoError(t, err, "SendTransaction failed", "tx", *tx) - err = network.AwaitTransactions(ctx, tx) - require.NoError(t, err) - watcher.Update() - receipt, err := client.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - - // check value goes to recipient - expected := tx.Value() - actual := watcher.Delta(recipient.Address) - assert.Equal(t, expected, actual, "Recipient's balance increase unexpected", "expected", expected.Int64(), "actual", actual.Int64()) - - // Check tip goes to validator - header, err := network[0].WsClient.HeaderByNumber(ctx, receipt.BlockNumber) - require.NoError(t, err) - gpm, err := network[0].Eth.APIBackend.GasPriceMinimumForHeader(ctx, nil, header) - require.NoError(t, err) - baseFee := new(big.Int).Mul(gpm, new(big.Int).SetUint64(receipt.GasUsed)) - switch tx.Type() { - case types.LegacyTxType, types.AccessListTxType: - fee := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(receipt.GasUsed)) - expected = new(big.Int).Sub(fee, baseFee) - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: - expected = tx.EffectiveGasTipValue(gpm) - expected.Mul(expected, new(big.Int).SetUint64(receipt.GasUsed)) - } - actual = watcher.Delta(node.Address) - assert.Equal(t, expected, actual, "Validator's balance increase unexpected", "expected", expected.Int64(), "actual", actual.Int64()) - - // check value + tx fee + gateway fee are subtracted from sender - var fee *big.Int - switch tx.Type() { - case types.LegacyTxType, types.AccessListTxType: - fee = new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(receipt.GasUsed)) - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: - tip := tx.EffectiveGasTipValue(gpm) - tip.Mul(tip, new(big.Int).SetUint64(receipt.GasUsed)) - fee = new(big.Int).Add(tip, baseFee) - } - consumed := new(big.Int).Add(tx.Value(), fee) - if tx.GatewayFeeRecipient() != nil && tx.GatewayFee() != nil { - consumed.Add(consumed, tx.GatewayFee()) - } - expected = new(big.Int).Neg(consumed) - actual = watcher.Delta(sender.Address) - assert.Equal(t, expected, actual, "Sender's balance decrease unexpected", "expected", expected.Int64(), "actual", expected.Int64()) - - // Check gateway fee - if tx.GatewayFeeRecipient() != nil && tx.GatewayFee() != nil { - expected = tx.GatewayFee() - actual = watcher.Delta(gateWayFeeRecipient.Address) - assert.Equal(t, expected, actual, "gateWayFeeRecipient's balance increase unexpected", "expected", expected.Int64(), "actual", actual.Int64()) - } - }) - } -} - // prepareTransaction prepares gasPrice, gasLimit and sign the transaction. -func prepareTransaction(txArgs ethapi.TransactionArgs, senderKey *ecdsa.PrivateKey, sender common.Address, signer types.Signer, client *ethclient.Client, isGingerbreadP2 bool) (*types.Transaction, error) { +func prepareTransaction(txArgs ethapi.TransactionArgs, senderKey *ecdsa.PrivateKey, sender common.Address, signer types.Signer, client *ethclient.Client) (*types.Transaction, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) defer cancel() @@ -441,7 +248,7 @@ func prepareTransaction(txArgs ethapi.TransactionArgs, senderKey *ecdsa.PrivateK } // Create the transaction and sign it - rawTx := txArgs.ToTransaction(isGingerbreadP2) + rawTx := txArgs.ToTransaction() signed, err := types.SignTx(rawTx, signer, senderKey) if err != nil { return nil, err @@ -509,7 +316,7 @@ func TestTransferERC20(t *testing.T) { blockNum, err := client.BlockNumber(ctx) require.NoError(t, err) signer := types.MakeSigner(devAccounts[0].ChainConfig, new(big.Int).SetUint64(blockNum)) - tx, err := prepareTransaction(*tc.txArgs, sender.Key, sender.Address, signer, client, true) + tx, err := prepareTransaction(*tc.txArgs, sender.Key, sender.Address, signer, client) require.NoError(t, err) err = client.SendTransaction(ctx, tx) if tc.expectedErr != nil { diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 68b5945cab..8f8b7ae0e6 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -331,6 +331,16 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* return r, err } +// BlockReceipts returns the receipts of a given block number or hash +func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.Receipt, error) { + var r []*types.Receipt + err := ec.c.CallContext(ctx, &r, "eth_getBlockReceipts", blockNrOrHash) + if err == nil && r == nil { + return nil, ethereum.NotFound + } + return r, err +} + type rpcProgress struct { StartingBlock hexutil.Uint64 CurrentBlock hexutil.Uint64 diff --git a/go.mod b/go.mod index 6219affceb..0997b51ea5 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,9 @@ module github.com/celo-org/celo-blockchain -go 1.15 +go 1.19 require ( - github.com/Azure/azure-pipeline-go v0.2.2 // indirect github.com/Azure/azure-storage-blob-go v0.7.0 - github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect - github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 github.com/aws/aws-sdk-go-v2 v1.2.0 github.com/aws/aws-sdk-go-v2/config v1.1.1 @@ -23,14 +20,10 @@ require ( github.com/consensys/gnark-crypto v0.12.1 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea - github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/dlclark/regexp2 v1.2.0 // indirect - github.com/docker/docker v24.0.7+incompatible + github.com/docker/docker v24.0.9+incompatible github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 github.com/fatih/color v1.7.0 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 - github.com/go-ole/go-ole v1.2.5 // indirect - github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect github.com/go-stack/stack v1.8.0 github.com/golang/protobuf v1.4.3 github.com/golang/snappy v0.0.4 @@ -46,16 +39,13 @@ require ( github.com/huin/goupnp v1.0.2 github.com/influxdata/influxdb v1.8.3 github.com/influxdata/influxdb-client-go/v2 v2.4.0 - github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e github.com/julienschmidt/httprouter v1.2.0 github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 - github.com/kylelemons/godebug v1.1.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 - github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/gomega v1.10.1 @@ -67,17 +57,63 @@ require ( github.com/shopspring/decimal v1.2.0 github.com/stretchr/testify v1.8.2 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef - golang.org/x/crypto v0.17.0 - golang.org/x/net v0.17.0 // indirect + golang.org/x/crypto v0.21.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.15.0 + golang.org/x/sys v0.18.0 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 +) + +require ( + filippo.io/edwards25519 v1.0.0-alpha.2 // indirect + github.com/Azure/azure-pipeline-go v0.2.2 // indirect + github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect + github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect + github.com/aws/smithy-go v1.1.0 // indirect + github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect + github.com/celo-org/celo-bls-go-android v0.3.3 // indirect + github.com/celo-org/celo-bls-go-ios v0.3.3 // indirect + github.com/celo-org/celo-bls-go-linux v0.3.3 // indirect + github.com/celo-org/celo-bls-go-macos v0.3.3 // indirect + github.com/celo-org/celo-bls-go-other v0.3.3 // indirect + github.com/celo-org/celo-bls-go-windows v0.3.3 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/deepmap/oapi-codegen v1.8.2 // indirect + github.com/dlclark/regexp2 v1.2.0 // indirect + github.com/go-ole/go-ole v1.2.5 // indirect + github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/naoina/go-stringutil v0.1.0 // indirect + github.com/opentracing/opentracing-go v1.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/tklauser/go-sysconf v0.3.5 // indirect + github.com/tklauser/numcpus v0.2.2 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/protobuf v1.23.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect ) // Use our fork which disables bitcode diff --git a/go.sum b/go.sum index dd05506296..0d5ee2481c 100644 --- a/go.sum +++ b/go.sum @@ -35,7 +35,6 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= @@ -85,12 +84,10 @@ github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13P github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.2 h1:/YOgUp25sdCnP5ho6Hl3s0E438zlX+Kak7E6TgBgoT0= github.com/btcsuite/btcd v0.23.2/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.1/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= -github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.1 h1:hDcDaXiP0uEzR8Biqo2weECKqEw0uHDZ9ixIWevVQqY= github.com/btcsuite/btcd/btcutil v1.1.1/go.mod h1:nbKlBMNm9FGsdvKvu0essceubPiAcI57pYBNnsLAa34= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= @@ -126,7 +123,6 @@ github.com/celo-org/mobile v0.0.0-20210324213558-66ac87d7fb95/go.mod h1:skQtrUTU github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -141,8 +137,6 @@ github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -165,8 +159,8 @@ github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMa github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= -github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498 h1:Y9vTBSsV4hSwPSj4bacAU/eSnV3dAxVpepaghAdhGoQ= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= @@ -321,19 +315,15 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= @@ -399,7 +389,6 @@ github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQm github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -423,12 +412,11 @@ github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1 github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -443,9 +431,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -475,7 +461,6 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -492,12 +477,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -523,9 +506,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -547,13 +527,10 @@ golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -566,7 +543,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -602,37 +578,18 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -667,9 +624,6 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -723,7 +677,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= diff --git a/graphql/graphql.go b/graphql/graphql.go index bfd2f777ba..7aa8505578 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -228,9 +228,9 @@ func (t *Transaction) GasPrice(ctx context.Context) (hexutil.Big, error) { switch tx.Type() { case types.AccessListTxType: return hexutil.Big(*tx.GasPrice()), nil - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: if t.block != nil { - if baseFee, _ := t.block.BaseFeePerGasForCurrency(ctx, tx.FeeCurrency()); baseFee != nil { + if baseFee, _ := t.block.BaseFeePerGasForCurrency(ctx, tx.DenominatedFeeCurrency()); baseFee != nil { // price = min(tip, gasFeeCap - baseFee) + baseFee return (hexutil.Big)(*math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())), nil } @@ -247,9 +247,9 @@ func (t *Transaction) EffectiveGasPrice(ctx context.Context) (*hexutil.Big, erro return nil, err } switch tx.Type() { - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: if t.block != nil { - if baseFee, _ := t.block.BaseFeePerGasForCurrency(ctx, tx.FeeCurrency()); baseFee != nil { + if baseFee, _ := t.block.BaseFeePerGasForCurrency(ctx, tx.DenominatedFeeCurrency()); baseFee != nil { // price = min(tip, gasFeeCap - baseFee) + baseFee return (*hexutil.Big)(math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee.ToInt()), tx.GasFeeCap())), nil } diff --git a/interfaces.go b/interfaces.go index 39102012a3..cce7465a00 100644 --- a/interfaces.go +++ b/interfaces.go @@ -117,6 +117,7 @@ type CallMsg struct { To *common.Address // the destination contract (nil for contract creation) Gas uint64 // if 0, the call executes with near-infinite gas FeeCurrency *common.Address // 0 for the native currency + MaxFeeInFeeCurrency *big.Int // Set iff it's a celo denominated tx. Maximum value of fees when converted to FeeCurrency. GatewayFeeRecipient *common.Address // 0 for no gateway fee GatewayFee *big.Int // 0 for no gateway fee GasPrice *big.Int // wei <-> gas exchange ratio diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 94281a5d7d..6d5346144e 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -426,7 +426,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *Transacti return nil, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction(s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number)) + tx := args.toTransaction() return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) } @@ -469,7 +469,7 @@ func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args Transactio return nil, fmt.Errorf("nonce not specified") } // Before actually signing the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction(s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number)) + tx := args.toTransaction() if err := checkFeeFromCeloTx(ctx, s.b, tx); err != nil { return nil, err } @@ -824,6 +824,42 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A return res[:], state.Error() } +// GetBlockReceipts returns the block receipts for the given block hash or number or tag. +func (s *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { + block, err := s.b.BlockByNumberOrHash(ctx, blockNrOrHash) + if block == nil || err != nil { + // When the block doesn't exist, the RPC method should return JSON null + // as per specification. + return nil, nil + } + receipts, err := s.b.GetReceipts(ctx, block.Hash()) + if err != nil { + return nil, err + } + txs := block.Transactions() + // We need to account for the block receipt, which if present will mean + // that there is one more receipt than transactions. + if len(txs) != len(receipts) && len(txs)+1 != len(receipts) { + return nil, fmt.Errorf("receipts length mismatch: %d vs %d", len(txs), len(receipts)) + } + + // Derive the sender. + signer := types.MakeSigner(s.b.ChainConfig(), block.Number()) + result := make([]map[string]interface{}, len(receipts)) + for i, receipt := range receipts { + var tx *types.Transaction + if i < len(txs) { + tx = txs[i] + } + result[i], err = generateReceiptResponse(ctx, s.b, receipt, signer, tx, block.Hash(), block.NumberU64(), uint64(i)) + if err != nil { + return nil, err + } + } + + return result, nil +} + // OverrideAccount indicates the overriding fields of account during the execution // of a message call. // Note, state and stateDiff can't be specified at the same time. If state is @@ -1313,9 +1349,9 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.TransactionIndex = (*hexutil.Uint64)(&index) } // Celo specifics - if tx.Type() == types.LegacyTxType || tx.Type() == types.CeloDynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxV2Type { + if tx.Type() == types.LegacyTxType || tx.Type() == types.CeloDynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxV2Type || tx.Type() == types.CeloDenominatedTxType { result.FeeCurrency = tx.FeeCurrency() - if tx.Type() != types.CeloDynamicFeeTxV2Type { + if tx.Type() == types.LegacyTxType || tx.Type() == types.CeloDynamicFeeTxType { result.GatewayFeeRecipient = tx.GatewayFeeRecipient() result.GatewayFee = (*hexutil.Big)(tx.GatewayFee()) } @@ -1326,7 +1362,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber al := tx.AccessList() result.Accesses = &al result.ChainID = (*hexutil.Big)(tx.ChainId()) - case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type: + case types.DynamicFeeTxType, types.CeloDynamicFeeTxType, types.CeloDynamicFeeTxV2Type, types.CeloDenominatedTxType: al := tx.AccessList() result.Accesses = &al result.ChainID = (*hexutil.Big)(tx.ChainId()) @@ -1335,7 +1371,12 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber // if the transaction has been mined, compute the effective gas price // if blockHash != (common.Hash{}) { // This is from upstream (check the function comment above). if inABlock { - baseFee, err := baseFeeFn(tx.FeeCurrency()) + var currency *common.Address = tx.FeeCurrency() + // Celo Denominated txs are denominated in celo + if tx.Type() == types.CeloDenominatedTxType { + currency = nil + } + baseFee, err := baseFeeFn(currency) if err == nil { // price = min(tip, gasFeeCap - baseFee) + baseFee price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap()) @@ -1489,7 +1530,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH vmRunner := b.NewEVMRunner(header, statedb) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), vmRunner, sysCtx) if err != nil { - return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction(false).Hash(), err) + return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) } if tracer.Equal(prevTracer) { return accessList, res.UsedGas, res.Err, nil @@ -1661,25 +1702,9 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha bigblock := new(big.Int).SetUint64(blockNumber) signer := types.MakeSigner(s.b.ChainConfig(), bigblock) - fields := generateReceiptResponse(receipt, signer, tx, blockHash, blockNumber, index) - // Assign the effective gas price paid - if !s.b.ChainConfig().IsLondon(bigblock) { - fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) - } else { - // var gasPrice *big.Int = new(big.Int) - if tx.Type() == types.DynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxV2Type { - header, err := s.b.HeaderByHash(ctx, blockHash) - if err != nil { - return nil, err - } - gasPriceMinimum, err := s.b.GasPriceMinimumForHeader(ctx, tx.FeeCurrency(), header) - if err == nil { - fields["effectiveGasPrice"] = hexutil.Uint64(new(big.Int).Add(gasPriceMinimum, tx.EffectiveGasTipValue(gasPriceMinimum)).Uint64()) - } - // if err != nil, it's due to a state prune. In this case no effectiveGasPrice will be returned. - } else { - fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) - } + fields, err := generateReceiptResponse(ctx, s.b, receipt, signer, tx, blockHash, blockNumber, index) + if err != nil { + return nil, err } return fields, nil } @@ -1709,7 +1734,10 @@ func (s *PublicTransactionPoolAPI) GetBlockReceipt(ctx context.Context, hash com } else { receipt = receipts[index] } - fields := generateReceiptResponse(receipt, nil, nil, hash, blockNumber, index) + fields, err := generateReceiptResponse(ctx, s.b, receipt, nil, nil, hash, blockNumber, index) + if err != nil { + return nil, err + } return fields, nil } @@ -1785,7 +1813,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Tra return common.Hash{}, err } // Assemble the transaction and sign with the wallet - tx := args.toTransaction(s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number)) + tx := args.toTransaction() signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) if err != nil { @@ -1803,7 +1831,7 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Tra return nil, err } // Assemble the transaction and obtain rlp - tx := args.toTransaction(s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number)) + tx := args.toTransaction() data, err := tx.MarshalBinary() if err != nil { return nil, err @@ -1869,7 +1897,7 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Tra return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. - tx := args.toTransaction(s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number)) + tx := args.toTransaction() if err := checkFeeFromCeloTx(ctx, s.b, tx); err != nil { return nil, err } @@ -1917,8 +1945,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs Transact if err := sendArgs.setDefaults(ctx, s.b); err != nil { return common.Hash{}, err } - isGingerbreadP2 := s.b.ChainConfig().IsGingerbreadP2(s.b.CurrentHeader().Number) - matchTx := sendArgs.toTransaction(isGingerbreadP2) + matchTx := sendArgs.toTransaction() // Before replacing the old transaction, ensure the _new_ transaction fee is reasonable. var price = matchTx.GasPrice() @@ -1948,7 +1975,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs Transact if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction(isGingerbreadP2)) + signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction()) if err != nil { return common.Hash{}, err } @@ -2070,8 +2097,8 @@ func toHexSlice(b [][]byte) []string { return r } -// generateReceiptResponse is a helper function which generates the response for GetTransactionReceipt() and GetBlockReceipt() -func generateReceiptResponse(receipt *types.Receipt, signer types.Signer, tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) map[string]interface{} { +// generateReceiptResponse is a helper function which generates the response for GetTransactionReceipt(), GetBlockReceipt() and GetBlockReceipts() +func generateReceiptResponse(ctx context.Context, backend Backend, receipt *types.Receipt, signer types.Signer, tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) (map[string]interface{}, error) { fields := map[string]interface{}{ "blockHash": blockHash, "blockNumber": hexutil.Uint64(blockNumber), @@ -2107,7 +2134,26 @@ func generateReceiptResponse(receipt *types.Receipt, signer types.Signer, tx *ty // Derive the sender. fields["from"], _ = types.Sender(signer, tx) fields["to"] = tx.To() - + // Assign the effective gas price paid + if backend.ChainConfig().IsLondon(new(big.Int).SetUint64(blockNumber)) { + fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) + } else { + // var gasPrice *big.Int = new(big.Int) + if tx.Type() == types.DynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxType || tx.Type() == types.CeloDynamicFeeTxV2Type || tx.Type() == types.CeloDenominatedTxType { + header, err := backend.HeaderByHash(ctx, blockHash) + if err != nil { + return nil, err + } + gasPriceMinimum, err := backend.GasPriceMinimumForHeader(ctx, tx.DenominatedFeeCurrency(), header) + if err == nil { + fields["effectiveGasPrice"] = hexutil.Uint64(new(big.Int).Add(gasPriceMinimum, tx.EffectiveGasTipValue(gasPriceMinimum)).Uint64()) + } + // if err != nil, it's due to a state prune. In this case no effectiveGasPrice will be returned. + } else { + fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64()) + } + } } - return fields + + return fields, nil } diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index a01e4c1978..2151e9591f 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -41,6 +41,7 @@ type TransactionArgs struct { MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` FeeCurrency *common.Address `json:"feeCurrency"` + MaxFeeInFeeCurrency *hexutil.Big `json:"maxFeeInFeeCurrency"` GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient"` GatewayFee *hexutil.Big `json:"gatewayFee"` Value *hexutil.Big `json:"value"` @@ -260,13 +261,14 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t if args.AccessList != nil { accessList = *args.AccessList } - msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, args.FeeCurrency, args.GatewayFeeRecipient, args.GatewayFee.ToInt(), data, accessList, args.EthCompatible, true) + maxFeeInFeeCurrency := args.MaxFeeInFeeCurrency.ToInt() + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, args.FeeCurrency, maxFeeInFeeCurrency, args.GatewayFeeRecipient, args.GatewayFee.ToInt(), data, accessList, args.EthCompatible, true) return msg, nil } // toTransaction converts the arguments to a transaction. // This assumes that setDefaults has been called. -func (args *TransactionArgs) toTransaction(isGingerbreadP2 bool) *types.Transaction { +func (args *TransactionArgs) toTransaction() *types.Transaction { var data types.TxData switch { case args.MaxFeePerGas != nil: @@ -274,8 +276,9 @@ func (args *TransactionArgs) toTransaction(isGingerbreadP2 bool) *types.Transact if args.AccessList != nil { al = *args.AccessList } - if args.GatewayFeeRecipient != nil || args.GatewayFee != nil || (!isGingerbreadP2 && args.FeeCurrency != nil) { - data = &types.CeloDynamicFeeTx{ + + if args.FeeCurrency != nil && args.MaxFeeInFeeCurrency != nil { + data = &types.CeloDenominatedTx{ To: args.To, ChainID: (*big.Int)(args.ChainID), Nonce: uint64(*args.Nonce), @@ -283,13 +286,12 @@ func (args *TransactionArgs) toTransaction(isGingerbreadP2 bool) *types.Transact GasFeeCap: (*big.Int)(args.MaxFeePerGas), GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), FeeCurrency: args.FeeCurrency, - GatewayFeeRecipient: args.GatewayFeeRecipient, - GatewayFee: (*big.Int)(args.GatewayFee), + MaxFeeInFeeCurrency: (*big.Int)(args.MaxFeeInFeeCurrency), Value: (*big.Int)(args.Value), Data: args.data(), AccessList: al, } - } else if isGingerbreadP2 && args.FeeCurrency != nil { + } else if args.FeeCurrency != nil { data = &types.CeloDynamicFeeTxV2{ To: args.To, ChainID: (*big.Int)(args.ChainID), @@ -347,8 +349,8 @@ func (args *TransactionArgs) toTransaction(isGingerbreadP2 bool) *types.Transact // ToTransaction converts the arguments to a transaction. // This assumes that setDefaults has been called. -func (args *TransactionArgs) ToTransaction(isGingerbread bool) *types.Transaction { - return args.toTransaction(isGingerbread) +func (args *TransactionArgs) ToTransaction() *types.Transaction { + return args.toTransaction() } func (args *TransactionArgs) checkEthCompatibility() error { diff --git a/internal/jsre/deps/web3.js b/internal/jsre/deps/web3.js index 950576f4d9..522002bff6 100644 --- a/internal/jsre/deps/web3.js +++ b/internal/jsre/deps/web3.js @@ -3696,7 +3696,7 @@ var outputBigNumberFormatter = function (number) { }; var isPredefinedBlockNumber = function (blockNumber) { - return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest'; + return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized'; }; var inputDefaultBlockNumberFormatter = function (blockNumber) { diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 551a728f80..ebdf3f3b0c 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -452,6 +452,11 @@ web3._extend({ params: 1, outputFormatter: web3._extend.formatters.outputTransactionReceiptFormatter }), + new web3._extend.Method({ + name: 'getBlockReceipts', + call: 'eth_getBlockReceipts', + params: 1, + }), new web3._extend.Method({ name: 'getRawTransaction', call: 'eth_getRawTransactionByHash', diff --git a/les/odr_test.go b/les/odr_test.go index 9eb7a8a0ad..99677d306e 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -140,7 +140,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(bankAddr) from.SetBalance(math.MaxBig256) - msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), new(big.Int), new(big.Int), nil, nil, new(big.Int), data, nil, false, true)} + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), new(big.Int), new(big.Int), nil, nil, nil, new(big.Int), data, nil, false, true)} context := core.NewEVMBlockContext(header, bc, nil) txContext := core.NewEVMTxContext(msg) @@ -154,7 +154,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai header := lc.GetHeaderByHash(bhash) state := light.NewState(ctx, header, lc.Odr()) state.SetBalance(bankAddr, math.MaxBig256) - msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), new(big.Int), new(big.Int), nil, nil, new(big.Int), data, nil, false, true)} + msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), new(big.Int), new(big.Int), nil, nil, nil, new(big.Int), data, nil, false, true)} context := core.NewEVMBlockContext(header, lc, nil) txContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true}) diff --git a/light/odr_test.go b/light/odr_test.go index 26c79a674b..92f22a4494 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -243,7 +243,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain // Perform read-only call. st.SetBalance(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), new(big.Int), new(big.Int), nil, nil, nil, data, nil, false, true)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), new(big.Int), new(big.Int), nil, nil, nil, nil, data, nil, false, true)} txContext := core.NewEVMTxContext(msg) context := core.NewEVMBlockContext(header, chain, nil) vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true}) diff --git a/light/txpool.go b/light/txpool.go index 1ade4456ac..6c06d24f1f 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -75,6 +75,7 @@ type TxPool struct { espresso bool // Fork indicator whether Espresso has been activated gingerbread bool // Fork indicator whether Gingerbread has been activated gingerbreadP2 bool // Fork indicator whether Gingerbread has been activated + hfork bool // Fork indicator whether HFork has been activated } // TxRelayBackend provides an interface to the mechanism that forwards transactions to the @@ -332,7 +333,8 @@ func (pool *TxPool) setNewHead(head *types.Header) { pool.donut = pool.config.IsDonut(next) pool.espresso = pool.config.IsEspresso(next) pool.gingerbread = pool.config.IsGingerbread(next) - pool.gingerbreadP2 = pool.config.IsGingerbread(next) + pool.gingerbreadP2 = pool.config.IsGingerbreadP2(next) + pool.hfork = pool.config.IsHFork(next) } // Stop stops the light transaction pool @@ -395,6 +397,10 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error if !pool.gingerbreadP2 && tx.Type() == types.CeloDynamicFeeTxV2Type { return core.ErrTxTypeNotSupported } + // Reject celo denominated fee until h fork + if !pool.hfork && tx.Type() == types.CeloDenominatedTxType { + return core.ErrTxTypeNotSupported + } // Validate the transaction sender and it's sig. Throw // if the from fields is invalid. diff --git a/mycelo/env/accounts.go b/mycelo/env/accounts.go index 7a80cce65a..dd38bc9e47 100644 --- a/mycelo/env/accounts.go +++ b/mycelo/env/accounts.go @@ -285,47 +285,3 @@ func DeriveAccountList(mnemonic string, accountType AccountType, qty int) ([]Acc return accounts, nil } - -// MustGenerateRandomAccount creates new account or panics -func MustGenerateRandomAccount() Account { - acc, err := GenerateRandomAccount() - if err != nil { - panic(err) - } - return acc -} - -// GenerateRandomAccount creates a random new account -func GenerateRandomAccount() (Account, error) { - privateKey, err := crypto.GenerateKey() - if err != nil { - return Account{}, err - } - return NewAccount(privateKey), nil -} - -// NewAccount creates a new account for the specified private key -func NewAccount(key *ecdsa.PrivateKey) Account { - return Account{ - PrivateKey: key, - Address: crypto.PubkeyToAddress(key.PublicKey), - } -} - -// UnmarshalJSON implements json.Unmarshaler -func (a *Account) UnmarshalJSON(b []byte) error { - var data struct { - PrivateKey string - Address common.Address - } - if err := json.Unmarshal(b, &data); err != nil { - return err - } - a.Address = data.Address - key, err := crypto.HexToECDSA(data.PrivateKey) - if err != nil { - return err - } - a.PrivateKey = key - return nil -} diff --git a/rpc/types.go b/rpc/types.go index 23f645911d..49e988c336 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -84,8 +84,10 @@ type RPCTransaction struct { EthCompatible bool `json:"ethCompatible"` } -// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: -// - "latest", "earliest" or "pending" as string arguments +// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It +// supports: - "finalized", latest", "earliest" or "pending" as string +// arguments where finalized is equivalent to latest since all blocks are final +// in celo. // - the block number // Returned errors: // - an invalid block number error when the given argument isn't a known strings @@ -106,6 +108,9 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { case "pending": *bn = PendingBlockNumber return nil + case "finalized": + *bn = LatestBlockNumber + return nil } blckNum, err := hexutil.DecodeUint64(input) @@ -172,6 +177,10 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error { bn := LatestBlockNumber bnh.BlockNumber = &bn return nil + case "finalized": + bn := LatestBlockNumber + bnh.BlockNumber = &bn + return nil case "pending": bn := PendingBlockNumber bnh.BlockNumber = &bn diff --git a/rpc/types_test.go b/rpc/types_test.go index ec80a14f35..8958b79018 100644 --- a/rpc/types_test.go +++ b/rpc/types_test.go @@ -45,9 +45,10 @@ func TestBlockNumberJSONUnmarshal(t *testing.T) { 11: {`"pending"`, false, PendingBlockNumber}, 12: {`"latest"`, false, LatestBlockNumber}, 13: {`"earliest"`, false, EarliestBlockNumber}, - 14: {`someString`, true, BlockNumber(0)}, - 15: {`""`, true, BlockNumber(0)}, - 16: {``, true, BlockNumber(0)}, + 14: {`"finalized"`, false, LatestBlockNumber}, + 15: {`someString`, true, BlockNumber(0)}, + 16: {`""`, true, BlockNumber(0)}, + 17: {``, true, BlockNumber(0)}, } for i, test := range tests { @@ -87,18 +88,20 @@ func TestBlockNumberOrHash_UnmarshalJSON(t *testing.T) { 11: {`"pending"`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, 12: {`"latest"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, 13: {`"earliest"`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 14: {`someString`, true, BlockNumberOrHash{}}, - 15: {`""`, true, BlockNumberOrHash{}}, - 16: {``, true, BlockNumberOrHash{}}, - 17: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 18: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, - 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, - 21: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, - 22: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, - 23: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, - 24: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, - 25: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, + 14: {`"finalized"`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 15: {`someString`, true, BlockNumberOrHash{}}, + 16: {`""`, true, BlockNumberOrHash{}}, + 17: {``, true, BlockNumberOrHash{}}, + 18: {`"0x0000000000000000000000000000000000000000000000000000000000000000"`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 19: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 20: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":false}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), false)}, + 21: {`{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","requireCanonical":true}`, false, BlockNumberOrHashWithHash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), true)}, + 22: {`{"blockNumber":"0x1"}`, false, BlockNumberOrHashWithNumber(1)}, + 23: {`{"blockNumber":"pending"}`, false, BlockNumberOrHashWithNumber(PendingBlockNumber)}, + 24: {`{"blockNumber":"latest"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 25: {`{"blockNumber":"earliest"}`, false, BlockNumberOrHashWithNumber(EarliestBlockNumber)}, + 26: {`{"blockNumber":"finalized"}`, false, BlockNumberOrHashWithNumber(LatestBlockNumber)}, + 27: {`{"blockNumber":"0x1", "blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000"}`, true, BlockNumberOrHash{}}, } for i, test := range tests { diff --git a/signer/core/api.go b/signer/core/api.go index bf608cdf42..45bda35bcf 100644 --- a/signer/core/api.go +++ b/signer/core/api.go @@ -565,9 +565,8 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args apitypes.SendTxA if err != nil { return nil, err } - // TODO Change flag after gingerbreadP2 activation // Convert fields into a real transaction - var unsignedTx = result.Transaction.ToTransaction(false) + var unsignedTx = result.Transaction.ToTransaction() // Get the password for the transaction pw, err := api.lookupOrQueryPassword(acc.Address, "Account password", fmt.Sprintf("Please enter the password for account %s", acc.Address.String())) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index cb1622c0d4..0e58b37eca 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -101,10 +101,10 @@ func (args SendTxArgs) String() string { } func (args SendTxArgs) CheckEthCompatibility() error { - return args.ToTransaction(false).CheckEthCompatibility() + return args.ToTransaction().CheckEthCompatibility() } -func (args *SendTxArgs) ToTransaction(isGingerbreadP2 bool) *types.Transaction { +func (args *SendTxArgs) ToTransaction() *types.Transaction { // Upstream refactored this method to copy what txArgs.ToTransaction is doing in // bb1f7ebf203f40dae714a3b8445918cfcfc9a7db in order to be able to compile the code to // WebAssembly. Duplicating this logic right now does not seem to be worth it for celo @@ -135,5 +135,5 @@ func (args *SendTxArgs) ToTransaction(isGingerbreadP2 bool) *types.Transaction { to := args.To.Address() txArgs.To = &to } - return txArgs.ToTransaction(isGingerbreadP2) + return txArgs.ToTransaction() } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index ce2ef86811..a8f1221581 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -346,7 +346,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Messa } msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice, - tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, nil, nil, nil, data, accessList, false, false) + tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, nil, nil, nil, nil, data, accessList, false, false) return msg, nil }