diff --git a/.circleci/config.yml b/.circleci/config.yml index d68676f6c6..10f5f0efa7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ end-to-end-defaults: &end-to-end-defaults docker: - image: celohq/node10-gcloud environment: - CELO_MONOREPO_BRANCH_TO_TEST: master + CELO_MONOREPO_BRANCH_TO_TEST: victor/gateway-fee jobs: unit-tests: diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index dffa61e4ae..8ba8cd334e 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -410,16 +410,17 @@ type callmsg struct { ethereum.CallMsg } -func (m callmsg) From() common.Address { return m.CallMsg.From } -func (m callmsg) Nonce() uint64 { return 0 } -func (m callmsg) CheckNonce() bool { return false } -func (m callmsg) To() *common.Address { return m.CallMsg.To } -func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) GasCurrency() *common.Address { return m.CallMsg.GasCurrency } -func (m callmsg) GasFeeRecipient() *common.Address { return m.CallMsg.GasFeeRecipient } -func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } -func (m callmsg) Value() *big.Int { return m.CallMsg.Value } -func (m callmsg) Data() []byte { return m.CallMsg.Data } +func (m callmsg) From() common.Address { return m.CallMsg.From } +func (m callmsg) Nonce() uint64 { return 0 } +func (m callmsg) CheckNonce() bool { return false } +func (m callmsg) To() *common.Address { return m.CallMsg.To } +func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } +func (m callmsg) FeeCurrency() *common.Address { return m.CallMsg.FeeCurrency } +func (m callmsg) GatewayFeeRecipient() *common.Address { return m.CallMsg.GatewayFeeRecipient } +func (m callmsg) GatewayFee() *big.Int { return m.CallMsg.GatewayFee } +func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } +func (m callmsg) Value() *big.Int { return m.CallMsg.Value } +func (m callmsg) Data() []byte { return m.CallMsg.Data } // filterBackend implements filters.Backend to support filtering for logs without // taking bloom-bits acceleration structures into account. diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index d746da4895..85c479896b 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -49,11 +49,12 @@ type TransactOpts struct { Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Signer SignerFn // Method to use for signing the transaction (mandatory) - Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) - GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) - GasCurrency *common.Address // Gas currency to be used for transaction (nil = default currency = Celo Gold) - GasFeeRecipient *common.Address // Address to which gas fees should be paid (nil = fees are returned to sender) - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) + Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) + GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) + FeeCurrency *common.Address // Fee currency to be used for transaction (nil = default currency = Celo Gold) + GatewayFeeRecipient *common.Address // Address to which gateway fees should be paid (nil = no gateway fees are paid) + GatewayFee *big.Int // Value of gateway fees to be paid (nil = no gateway fees are paid) + GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) } @@ -209,17 +210,19 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i return nil, fmt.Errorf("failed to suggest gas price: %v", err) } } - gasCurrency := opts.GasCurrency - // TODO(ashishb): Add SuggestGasCurrency to Transactor to get gas currency + + feeCurrency := opts.FeeCurrency + // TODO(nategraf): Add SuggestFeeCurrency to Transactor to get fee currency // Otherwise, the user might not be able to pay in non-native currency for contract // deployment. Paying for Contract deployment in non-native currency might not work right now. // Only paying for token transfer in non-native currency is supported. - //if gasCurrency == 0 { - // gasCurrency = c.transactor.SuggestGasCurrency(opts.Context) + //if feeCurrency == 0 { + // feeCurrency = c.transactor.SuggestFeeCurrency(opts.Context) //} - gasFeeRecipient := opts.GasFeeRecipient - // TODO(asa): Add SuggestGasFeeRecipient to Transactor. + gatewayFeeRecipient := opts.GatewayFeeRecipient + gatewayFee := opts.GatewayFee + // TODO(nategraf): Add SuggestGatewayFee to Transactor. gasLimit := opts.GasLimit if gasLimit == 0 { @@ -241,9 +244,9 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i // Create the transaction, sign it and schedule it for execution var rawTx *types.Transaction if contract == nil { - rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, gasCurrency, gasFeeRecipient, input) + rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, feeCurrency, gatewayFeeRecipient, gatewayFee, input) } else { - rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, gasCurrency, gasFeeRecipient, input) + rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, feeCurrency, gatewayFeeRecipient, gatewayFee, input) } if opts.Signer == nil { return nil, errors.New("no signer to authorize the transaction with") diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index 87218fd47d..e48197fb82 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) { ) // Create the transaction. - tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), nil, nil, common.FromHex(test.code)) + tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), nil, nil, nil, common.FromHex(test.code)) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) // Wait for it to get mined in the background. diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 82f23ffb0b..ab2e611af5 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -472,7 +472,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) - tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil, nil, nil) + tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil, nil, nil, nil) signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID) if err != nil { f.lock.Unlock() diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 467a359365..a3c61db90b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -203,6 +203,11 @@ var ( Usage: "Public address for transaction broadcasting and block mining rewards (default = first account)", Value: "0", } + GatewayFeeFlag = BigFlag{ + Name: "gatewayfee", + Usage: "Minimum value of gateway fee to serve a light client transaction", + Value: eth.DefaultConfig.GatewayFee, + } BLSbaseFlag = cli.StringFlag{ Name: "blsbase", Usage: "Public address for block mining BLS signatures (default = first account created)", @@ -1415,6 +1420,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if ctx.GlobalIsSet(EVMInterpreterFlag.Name) { cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name) } + if ctx.GlobalIsSet(GatewayFeeFlag.Name) { + cfg.GatewayFee = GlobalBig(ctx, GatewayFeeFlag.Name) + } // Override any default configs for hard coded networks. switch { diff --git a/contract_comm/blockchain_parameters/blockchain_parameters.go b/contract_comm/blockchain_parameters/blockchain_parameters.go index 34d8e0845b..152a894c5f 100644 --- a/contract_comm/blockchain_parameters/blockchain_parameters.go +++ b/contract_comm/blockchain_parameters/blockchain_parameters.go @@ -69,7 +69,7 @@ const ( { "constant": true, "inputs": [], - "name": "intrinsicGasForAlternativeGasCurrency", + "name": "intrinsicGasForAlternativeFeeCurrency", "outputs": [ { "name": "", @@ -133,8 +133,8 @@ func GetGasCost(header *types.Header, state vm.StateDB, defaultGas uint64, metho return gas.Uint64() } -func GetIntrinsicGasForAlternativeGasCurrency(header *types.Header, state vm.StateDB) uint64 { - return GetGasCost(header, state, params.IntrinsicGasForAlternativeGasCurrency, "intrinsicGasForAlternativeGasCurrency") +func GetIntrinsicGasForAlternativeFeeCurrency(header *types.Header, state vm.StateDB) uint64 { + return GetGasCost(header, state, params.IntrinsicGasForAlternativeFeeCurrency, "intrinsicGasForAlternativeFeeCurrency") } func CheckMinimumVersion(header *types.Header, state vm.StateDB) { diff --git a/contract_comm/currency/currency.go b/contract_comm/currency/currency.go index c9c0cb460e..59d650430f 100644 --- a/contract_comm/currency/currency.go +++ b/contract_comm/currency/currency.go @@ -77,7 +77,7 @@ const ( "type": "function" }]` - // This is taken from celo-monorepo/packages/protocol/build//contracts/GasCurrency.json + // This is taken from celo-monorepo/packages/protocol/build//contracts/FeeCurrency.json getWhitelistABI = `[{"constant": true, "inputs": [], "name": "getWhitelist", @@ -190,12 +190,12 @@ func getExchangeRate(currencyAddress *common.Address) (*exchangeRate, error) { log.Warn("Registry address lookup failed", "err", err) return &exchangeRate{big.NewInt(1), big.NewInt(1)}, err } else { - log.Error("medianRate invocation error", "gasCurrencyAddress", currencyAddress.Hex(), "leftoverGas", leftoverGas, "err", err) + log.Error("medianRate invocation error", "feeCurrencyAddress", currencyAddress.Hex(), "leftoverGas", leftoverGas, "err", err) return &exchangeRate{big.NewInt(1), big.NewInt(1)}, err } } } - log.Trace("medianRate invocation success", "gasCurrencyAddress", currencyAddress, "returnArray", returnArray, "leftoverGas", leftoverGas) + log.Trace("medianRate invocation success", "feeCurrencyAddress", currencyAddress, "returnArray", returnArray, "leftoverGas", leftoverGas) return &exchangeRate{returnArray[0], returnArray[1]}, nil } @@ -217,12 +217,12 @@ func GetBalanceOf(accountOwner common.Address, contractAddress common.Address, g } // ------------------------------ -// GasCurrencyWhiteList Functions +// FeeCurrencyWhiteList Functions //------------------------------- func retrieveWhitelist(header *types.Header, state vm.StateDB) ([]common.Address, error) { returnList := []common.Address{} - _, err := contract_comm.MakeStaticCall(params.GasCurrencyWhitelistRegistryId, getWhitelistFuncABI, "getWhitelist", []interface{}{}, &returnList, params.MaxGasForGetWhiteList, header, state) + _, err := contract_comm.MakeStaticCall(params.FeeCurrencyWhitelistRegistryId, getWhitelistFuncABI, "getWhitelist", []interface{}{}, &returnList, params.MaxGasForGetWhiteList, header, state) if err != nil { if err == errors.ErrSmartContractNotDeployed { log.Warn("Registry address lookup failed", "err", err) @@ -239,7 +239,7 @@ func retrieveWhitelist(header *types.Header, state vm.StateDB) ([]common.Address func IsWhitelisted(currencyAddress common.Address, header *types.Header, state vm.StateDB) bool { whitelist, err := retrieveWhitelist(header, state) if err != nil { - log.Warn("Failed to get gas currency whitelist", "err", err) + log.Warn("Failed to get fee currency whitelist", "err", err) return true } return containsCurrency(currencyAddress, whitelist) @@ -257,7 +257,7 @@ func containsCurrency(currencyAddr common.Address, currencyList []common.Address func CurrencyWhitelist(header *types.Header, state vm.StateDB) ([]common.Address, error) { whitelist, err := retrieveWhitelist(header, state) if err != nil { - log.Warn("Failed to get gas currency whitelist", "err", err) + log.Warn("Failed to get fee currency whitelist", "err", err) } return whitelist, err } diff --git a/contract_comm/evm.go b/contract_comm/evm.go index d2e24590c0..5dabb13deb 100644 --- a/contract_comm/evm.go +++ b/contract_comm/evm.go @@ -34,7 +34,7 @@ import ( // NOTE: Any changes made to this file should be duplicated to core/evm.go! var ( - emptyMessage = types.NewMessage(common.HexToAddress("0x0"), nil, 0, common.Big0, 0, common.Big0, nil, nil, []byte{}, false) + emptyMessage = types.NewMessage(common.HexToAddress("0x0"), nil, 0, common.Big0, 0, common.Big0, nil, nil, common.Big0, []byte{}, false) internalEvmHandlerSingleton *InternalEVMHandler ) diff --git a/core/bench_test.go b/core/bench_test.go index 82c62476d5..aa7fbd37c8 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -86,7 +86,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) gas, _ := IntrinsicGas(data, false, false, nil, nil, nil) - tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, nil, nil, data), types.HomesteadSigner{}, benchRootKey) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, nil, nil, nil, data), types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } } @@ -128,6 +128,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { nil, nil, nil, + nil, ) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from]) gen.AddTx(tx) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 21be49644c..03a54bec6a 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -620,7 +620,7 @@ func TestFastVsFullChains(t *testing.T) { // If the block number is multiple of 3, send a few bonus transactions to the miner if i%3 == 2 { for j := 0; j < i%4+1; j++ { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key) if err != nil { panic(err) } @@ -793,8 +793,8 @@ func TestChainTxReorgs(t *testing.T) { // Create two transactions shared between the chains: // - postponed: transaction included at a later block in the forked chain // - swapped: transaction included at the same block number in the forked chain - postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key1) - swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key1) + postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key1) + swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block @@ -810,13 +810,13 @@ func TestChainTxReorgs(t *testing.T) { chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { switch i { case 0: - pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key2) + pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key2) gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork case 2: - freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key2) + freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key2) gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(swapped) // This transaction will be swapped out at the exact height @@ -835,18 +835,18 @@ func TestChainTxReorgs(t *testing.T) { chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { switch i { case 0: - pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key3) gen.AddTx(pastAdd) // This transaction needs to be injected during reorg case 2: gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain - freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key3) gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time case 3: - futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key3) + futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) @@ -902,7 +902,7 @@ func TestLogReorgs(t *testing.T) { blockchain.SubscribeRemovedLogsEvent(rmLogsCh) chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { if i == 1 { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil, nil, code), signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil, nil, nil, code), signer, key1) if err != nil { t.Fatalf("failed to create tx: %v", err) } @@ -951,7 +951,7 @@ func TestReorgSideEvent(t *testing.T) { } replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil, nil, nil), signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil, nil, nil, nil), signer, key1) if i == 2 { gen.OffsetTime(-9) } @@ -1079,7 +1079,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil, nil), signer, key) } ) switch i { @@ -1142,7 +1142,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil, nil, nil, nil), signer, key) } ) if i == 0 { @@ -1189,11 +1189,11 @@ func TestEIP161AccountRemoval(t *testing.T) { ) switch i { case 0: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, nil), signer, key) case 1: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, nil), signer, key) case 2: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil, nil, nil, nil), signer, key) } if err != nil { t.Fatal(err) @@ -1402,7 +1402,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in uniq := uint64(i*numTxs + txi) recipient := recipientFn(uniq) //recipient := common.BigToAddress(big.NewInt(0).SetUint64(1337 + uniq)) - tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil, nil, nil), signer, testBankKey) + tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil, nil, nil, nil), signer, testBankKey) if err != nil { b.Error(err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index b88cd99e91..b742c9168b 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -54,13 +54,13 @@ func ExampleGenerateChain() { switch i { case 0: // In block 1, addr1 sends addr2 some ether. - tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, key1) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), signer, key1) gen.AddTx(tx) case 1: // In block 2, addr1 sends some more ether to addr2. // addr2 passes it on to addr3. - tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key1) - tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, key2) + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, key2) gen.AddTx(tx1) gen.AddTx(tx2) case 2: diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go index dcdb9439a1..0036da48b7 100644 --- a/core/rawdb/accessors_indexes_test.go +++ b/core/rawdb/accessors_indexes_test.go @@ -29,9 +29,9 @@ import ( func TestLookupStorage(t *testing.T) { db := ethdb.NewMemDatabase() - tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), nil, nil, []byte{0x11, 0x11, 0x11}) - tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), nil, nil, []byte{0x22, 0x22, 0x22}) - tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), nil, nil, []byte{0x33, 0x33, 0x33}) + tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), nil, nil, nil, []byte{0x11, 0x11, 0x11}) + tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), nil, nil, nil, []byte{0x22, 0x22, 0x22}) + tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), nil, nil, nil, []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil, nil) diff --git a/core/state_transition.go b/core/state_transition.go index c48889bd42..67c3306094 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -34,10 +34,10 @@ import ( ) var ( - ErrGasPriceDoesNotExceedMinimum = errors.New("gasprice does not exceed gas price minimum") + ErrGasPriceDoesNotExceedMinimum = errors.New("gasprice is less than gas price minimum") - errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") - errNonWhitelistedGasCurrency = errors.New("non-whitelisted gas currency address") + errInsufficientBalanceForFees = errors.New("insufficient balance to pay for fees") + errNonWhitelistedFeeCurrency = errors.New("non-whitelisted fee currency address") ) /* @@ -78,11 +78,13 @@ type Message interface { GasPrice() *big.Int Gas() uint64 + + // FeeCurrency specifies the currency for gas and gateway fees. // nil correspond to Celo Gold (native currency). // All other values should correspond to ERC20 contract addresses extended to be compatible with gas payments. - GasCurrency() *common.Address - // TODO: GasFeeRecipient is currently inactive and will be replaced by GatewayFeeRecipient. - GasFeeRecipient() *common.Address + FeeCurrency() *common.Address + GatewayFeeRecipient() *common.Address + GatewayFee() *big.Int Value() *big.Int Nonce() uint64 @@ -91,7 +93,7 @@ type Message interface { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, contractCreation, homestead bool, header *types.Header, state vm.StateDB, gasCurrency *common.Address) (uint64, error) { +func IntrinsicGas(data []byte, contractCreation, homestead bool, header *types.Header, state vm.StateDB, feeCurrency *common.Address) (uint64, error) { // Set the starting gas for the raw transaction var gas uint64 if contractCreation && homestead { @@ -133,8 +135,8 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool, header *types.H // min(gas sent - gas charged, maxGasForDebitAndCreditTransactions) extra. // In this case, however, the user always ends up paying maxGasForDebitAndCreditTransactions // keeping it consistent. - if gasCurrency != nil { - gas += blockchain_parameters.GetIntrinsicGasForAlternativeGasCurrency(header, state) + if feeCurrency != nil { + gas += blockchain_parameters.GetIntrinsicGasForAlternativeFeeCurrency(header, state) } return gas, nil @@ -142,7 +144,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool, header *types.H // NewStateTransition initialises and returns a new state transition object. func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { - gasPriceMinimum, _ := gpm.GetGasPriceMinimum(msg.GasCurrency(), evm.GetHeader(), evm.GetStateDB()) + gasPriceMinimum, _ := gpm.GetGasPriceMinimum(msg.FeeCurrency(), evm.GetHeader(), evm.GetStateDB()) return &StateTransition{ gp: gp, @@ -164,7 +166,7 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { - log.Trace("Applying state transition message", "from", msg.From(), "nonce", msg.Nonce(), "to", msg.To(), "gas price", msg.GasPrice(), "gas currency", msg.GasCurrency(), "gas fee recipient", msg.GasFeeRecipient(), "gas", msg.Gas(), "value", msg.Value(), "data", msg.Data()) + log.Trace("Applying state transition message", "from", msg.From(), "nonce", msg.Nonce(), "to", msg.To(), "gas price", msg.GasPrice(), "fee currency", msg.FeeCurrency(), "gateway fee recipient", msg.GatewayFeeRecipient(), "gateway fee", msg.GatewayFee(), "gas", msg.Gas(), "value", msg.Value(), "data", msg.Data()) return NewStateTransition(evm, msg, gp).TransitionDb() } @@ -185,16 +187,22 @@ func (st *StateTransition) useGas(amount uint64) error { return nil } -func (st *StateTransition) buyGas() error { - mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) +// payFees deducts gas and gateway fees from sender balance and adds the purchased amount of gas to the state. +func (st *StateTransition) payFees() error { + feeVal := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) + + // If GatewayFeeRecipient is unspecified, the gateway fee value is ignore and the sender is not charged. + if st.msg.GatewayFeeRecipient() != nil { + feeVal.Add(feeVal, st.msg.GatewayFee()) + } - if st.msg.GasCurrency() != nil && (!currency.IsWhitelisted(*st.msg.GasCurrency(), st.evm.GetHeader(), st.evm.GetStateDB())) { - log.Trace("Gas currency not whitelisted", "gas currency address", st.msg.GasCurrency()) - return errNonWhitelistedGasCurrency + if st.msg.FeeCurrency() != nil && (!currency.IsWhitelisted(*st.msg.FeeCurrency(), st.evm.GetHeader(), st.evm.GetStateDB())) { + log.Trace("Fee currency not whitelisted", "fee currency address", st.msg.FeeCurrency()) + return errNonWhitelistedFeeCurrency } - if !st.canBuyGas(st.msg.From(), mgval, st.msg.GasCurrency()) { - return errInsufficientBalanceForGas + if !st.canPayFee(st.msg.From(), feeVal, st.msg.FeeCurrency()) { + return errInsufficientBalanceForFees } if err := st.gp.SubGas(st.msg.Gas()); err != nil { return err @@ -202,24 +210,24 @@ func (st *StateTransition) buyGas() error { st.initialGas = st.msg.Gas() st.gas += st.msg.Gas() - err := st.debitGas(st.msg.From(), mgval, st.msg.GasCurrency()) + err := st.debitFee(st.msg.From(), feeVal, st.msg.FeeCurrency()) return err } -func (st *StateTransition) canBuyGas(accountOwner common.Address, gasNeeded *big.Int, gasCurrency *common.Address) bool { - if gasCurrency == nil { - return st.state.GetBalance(accountOwner).Cmp(gasNeeded) > 0 +func (st *StateTransition) canPayFee(accountOwner common.Address, fee *big.Int, feeCurrency *common.Address) bool { + if feeCurrency == nil { + return st.state.GetBalance(accountOwner).Cmp(fee) >= 0 } - balanceOf, gasUsed, err := currency.GetBalanceOf(accountOwner, *gasCurrency, params.MaxGasToReadErc20Balance, st.evm.GetHeader(), st.evm.GetStateDB()) - log.Debug("balanceOf called", "gasCurrency", *gasCurrency, "gasUsed", gasUsed) + balanceOf, gasUsed, err := currency.GetBalanceOf(accountOwner, *feeCurrency, params.MaxGasToReadErc20Balance, st.evm.GetHeader(), st.evm.GetStateDB()) + log.Debug("balanceOf called", "feeCurrency", *feeCurrency, "gasUsed", gasUsed) if err != nil { return false } - return balanceOf.Cmp(gasNeeded) > 0 + return balanceOf.Cmp(fee) > 0 } -func (st *StateTransition) debitFrom(address common.Address, amount *big.Int, gasCurrency *common.Address) error { +func (st *StateTransition) debitFrom(address common.Address, amount *big.Int, feeCurrency *common.Address) error { if amount.Cmp(big.NewInt(0)) == 0 { return nil } @@ -234,13 +242,13 @@ func (st *StateTransition) debitFrom(address common.Address, amount *big.Int, ga rootCaller := vm.AccountRef(common.HexToAddress("0x0")) // The caller was already charged for the cost of this operation via IntrinsicGas. - _, leftoverGas, err := evm.Call(rootCaller, *gasCurrency, transactionData, params.MaxGasForDebitFromTransactions, big.NewInt(0)) + _, leftoverGas, err := evm.Call(rootCaller, *feeCurrency, transactionData, params.MaxGasForDebitFromTransactions, big.NewInt(0)) gasUsed := params.MaxGasForDebitFromTransactions - leftoverGas - log.Debug("debitFrom called", "gasCurrency", *gasCurrency, "gasUsed", gasUsed) + log.Debug("debitFrom called", "feeCurrency", *feeCurrency, "gasUsed", gasUsed) return err } -func (st *StateTransition) creditTo(address common.Address, amount *big.Int, gasCurrency *common.Address) error { +func (st *StateTransition) creditTo(address common.Address, amount *big.Int, feeCurrency *common.Address) error { if amount.Cmp(big.NewInt(0)) == 0 { return nil } @@ -254,31 +262,30 @@ func (st *StateTransition) creditTo(address common.Address, amount *big.Int, gas transactionData := common.GetEncodedAbi(functionSelector, [][]byte{common.AddressToAbi(address), common.AmountToAbi(amount)}) rootCaller := vm.AccountRef(common.HexToAddress("0x0")) // The caller was already charged for the cost of this operation via IntrinsicGas. - _, leftoverGas, err := evm.Call(rootCaller, *gasCurrency, transactionData, params.MaxGasForCreditToTransactions, big.NewInt(0)) + _, leftoverGas, err := evm.Call(rootCaller, *feeCurrency, transactionData, params.MaxGasForCreditToTransactions, big.NewInt(0)) gasUsed := params.MaxGasForCreditToTransactions - leftoverGas - log.Debug("creditTo called", "gasCurrency", *gasCurrency, "gasUsed", gasUsed) + log.Debug("creditTo called", "feeCurrency", *feeCurrency, "gasUsed", gasUsed) return err } -func (st *StateTransition) debitGas(from common.Address, amount *big.Int, gasCurrency *common.Address) (err error) { - log.Trace("Debiting gas", "from", from, "amount", amount, "gasCurrency", gasCurrency) +func (st *StateTransition) debitFee(from common.Address, amount *big.Int, feeCurrency *common.Address) (err error) { + log.Trace("Debiting fee", "from", from, "amount", amount, "feeCurrency", feeCurrency) // native currency - if gasCurrency == nil { + if feeCurrency == nil { st.state.SubBalance(from, amount) return nil } else { - return st.debitFrom(from, amount, gasCurrency) + return st.debitFrom(from, amount, feeCurrency) } } -func (st *StateTransition) creditGas(to common.Address, amount *big.Int, gasCurrency *common.Address) (err error) { - log.Trace("Crediting gas", "recipient", to, "amount", amount, "gasCurrency", gasCurrency) +func (st *StateTransition) creditFee(to common.Address, amount *big.Int, feeCurrency *common.Address) (err error) { // native currency - if gasCurrency == nil { + if feeCurrency == nil { st.state.AddBalance(to, amount) return nil } else { - return st.creditTo(to, amount, gasCurrency) + return st.creditTo(to, amount, feeCurrency) } } @@ -317,7 +324,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo contractCreation := msg.To() == nil // Calculate intrinsic gas. - gas, err := IntrinsicGas(st.data, contractCreation, homestead, st.evm.GetHeader(), st.state, msg.GasCurrency()) + gas, err := IntrinsicGas(st.data, contractCreation, homestead, st.evm.GetHeader(), st.state, msg.FeeCurrency()) if err != nil { return nil, 0, false, err } @@ -327,11 +334,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo log.Error("Transaction failed provide intrinsic gas", "err", err, "gas required", gas, "gas provided", st.msg.Gas(), - "gas currency", st.msg.GasCurrency()) + "fee currency", st.msg.FeeCurrency()) return nil, 0, false, vm.ErrOutOfGas } - err = st.buyGas() + err = st.payFees() if err != nil { log.Error("Transaction failed to buy gas", "err", err, "gas", gas) return nil, 0, false, err @@ -387,7 +394,17 @@ func (st *StateTransition) distributeTxFees() error { baseTxFee := new(big.Int).Mul(gasUsed, st.gasPriceMinimum) tipTxFee := new(big.Int).Sub(totalTxFee, baseTxFee) - if err := st.creditGas(st.evm.Coinbase, tipTxFee, st.msg.GasCurrency()); err != nil { + // Pay gateway fee to the specified recipient. + if st.msg.GatewayFeeRecipient() != nil { + log.Trace("Crediting gateway fee", "recipient", *st.msg.GatewayFeeRecipient(), "amount", st.msg.GatewayFee(), "feeCurrency", st.msg.FeeCurrency()) + if err := st.creditFee(*st.msg.GatewayFeeRecipient(), st.msg.GatewayFee(), st.msg.FeeCurrency()); err != nil { + log.Error("Failed to credit gateway fee", "err", err) + return err + } + } + + log.Trace("Crediting gas fee tip", "recipient", st.evm.Coinbase, "amount", tipTxFee, "feeCurrency", st.msg.FeeCurrency()) + if err := st.creditFee(st.evm.Coinbase, tipTxFee, st.msg.FeeCurrency()); err != nil { return err } @@ -400,12 +417,14 @@ func (st *StateTransition) distributeTxFees() error { log.Trace("Cannot credit gas fee to infrastructure fund: refunding fee to sender", "error", err, "fee", baseTxFee) refund.Add(refund, baseTxFee) } else { - if err = st.creditGas(*governanceAddress, baseTxFee, st.msg.GasCurrency()); err != nil { + log.Trace("Crediting gas fee tip", "recipient", *governanceAddress, "amount", baseTxFee, "feeCurrency", st.msg.FeeCurrency()) + if err = st.creditFee(*governanceAddress, baseTxFee, st.msg.FeeCurrency()); err != nil { return err } } - err = st.creditGas(st.msg.From(), refund, st.msg.GasCurrency()) + log.Trace("Crediting refund", "recipient", st.msg.From(), "amount", refund, "feeCurrency", st.msg.FeeCurrency()) + err = st.creditFee(st.msg.From(), refund, st.msg.FeeCurrency()) if err != nil { log.Error("Failed to refund gas", "err", err) return err diff --git a/core/tx_list.go b/core/tx_list.go index 7a38612746..60c5817b2c 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -298,13 +298,13 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions // Filter out all the transactions above the account's funds removed := l.txs.Filter(func(tx *types.Transaction) bool { - if tx.GasCurrency() == nil { - log.Trace("Transaction Filter", "hash", tx.Hash(), "Gas currency", tx.GasCurrency(), "Cost", tx.Cost(), "Cost Limit", costLimit, "Gas", tx.Gas(), "Gas Limit", gasLimit) + if tx.FeeCurrency() == nil { + log.Trace("Transaction Filter", "hash", tx.Hash(), "Fee currency", tx.FeeCurrency(), "Cost", tx.Cost(), "Cost Limit", costLimit, "Gas", tx.Gas(), "Gas Limit", gasLimit) return tx.Cost().Cmp(costLimit) > 0 || tx.Gas() > gasLimit } else { - // If the gas is being paid in the non-native currency, ensure that the `tx.Value` is less than costLimit - // as the gas price will be deducted in the non-native currency. - log.Trace("Transaction Filter", "hash", tx.Hash(), "Gas currency", tx.GasCurrency(), "Value", tx.Value(), "Cost Limit", costLimit, "Gas", tx.Gas(), "Gas Limit", gasLimit) + // If the fees are being paid in the non-native currency, ensure that the `tx.Value` is less than costLimit + // as the fees will be deducted in the non-native currency. + log.Trace("Transaction Filter", "hash", tx.Hash(), "Fee currency", tx.FeeCurrency(), "Value", tx.Value(), "Cost Limit", costLimit, "Gas", tx.Gas(), "Gas Limit", gasLimit) return tx.Value().Cmp(costLimit) > 0 || tx.Gas() > gasLimit } }) @@ -425,14 +425,14 @@ func newTxPricedList(all *txLookup) *txPricedList { // Gets the price heap for the given currency func (l *txPricedList) getPriceHeap(tx *types.Transaction) *priceHeap { - gasCurrency := tx.GasCurrency() - if gasCurrency == nil { + feeCurrency := tx.FeeCurrency() + if feeCurrency == nil { return l.nilCurrencyHeap } else { - if _, ok := l.nonNilCurrencyHeaps[*gasCurrency]; !ok { - l.nonNilCurrencyHeaps[*gasCurrency] = new(priceHeap) + if _, ok := l.nonNilCurrencyHeaps[*feeCurrency]; !ok { + l.nonNilCurrencyHeaps[*feeCurrency] = new(priceHeap) } - return l.nonNilCurrencyHeaps[*gasCurrency] + return l.nonNilCurrencyHeaps[*feeCurrency] } } @@ -455,9 +455,9 @@ func (l *txPricedList) Removed() { reheapNilCurrencyHeap := make(priceHeap, 0, l.all.nilCurrencyTxCurrCount) reheapNonNilCurrencyMap := make(map[common.Address]*priceHeap) - for gasCurrency, count := range l.all.nonNilCurrencyTxCurrCount { + for feeCurrency, count := range l.all.nonNilCurrencyTxCurrCount { reheapNonNilCurrencyHeap := make(priceHeap, 0, count) - reheapNonNilCurrencyMap[gasCurrency] = &reheapNonNilCurrencyHeap + reheapNonNilCurrencyMap[feeCurrency] = &reheapNonNilCurrencyHeap } l.stales, l.nonNilCurrencyHeaps, l.nilCurrencyHeap = 0, reheapNonNilCurrencyMap, &reheapNilCurrencyHeap @@ -488,7 +488,7 @@ func (l *txPricedList) Cap(cgThreshold *big.Int, local *accountSet) types.Transa continue } - if currency.Cmp(tx.GasPrice(), tx.GasCurrency(), cgThreshold, nil) >= 0 { + if currency.Cmp(tx.GasPrice(), tx.FeeCurrency(), cgThreshold, nil) >= 0 { save = append(save, tx) break } @@ -530,7 +530,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo } cheapest := l.getMinPricedTx() - return currency.Cmp(cheapest.GasPrice(), cheapest.GasCurrency(), tx.GasPrice(), tx.GasCurrency()) >= 0 + return currency.Cmp(cheapest.GasPrice(), cheapest.FeeCurrency(), tx.GasPrice(), tx.FeeCurrency()) >= 0 } // Discard finds a number of most underpriced transactions, removes them from the @@ -578,7 +578,7 @@ func (l *txPricedList) getHeapWithMinHead() (*priceHeap, *types.Transaction) { cheapestTxn = []*types.Transaction(*cheapestHeap)[0] } else { txn := []*types.Transaction(*priceHeap)[0] - if currency.Cmp(txn.GasPrice(), txn.GasCurrency(), cheapestTxn.GasPrice(), cheapestTxn.GasCurrency()) < 0 { + if currency.Cmp(txn.GasPrice(), txn.FeeCurrency(), cheapestTxn.GasPrice(), cheapestTxn.FeeCurrency()) < 0 { cheapestHeap = priceHeap } } diff --git a/core/tx_pool.go b/core/tx_pool.go index f45d705d96..7dde7935c2 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -63,7 +63,7 @@ var ( // ErrInsufficientFunds is returned if the total cost of executing a transaction // is higher than the balance of the user's account. - ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value") + ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value + gatewayFee") // ErrIntrinsicGas is returned if the transaction is specified to use less gas // than required to start the invocation. @@ -82,8 +82,8 @@ var ( // making the transaction invalid, rather a DOS protection. ErrOversizedData = errors.New("oversized data") - // ErrNonWhitelistedGasCurrency is returned if the txn gas currency is not white listed - ErrNonWhitelistedGasCurrency = errors.New("non-whitelisted gas currency") + // ErrNonWhitelistedFeeCurrency is returned if the txn fee currency is not white listed + ErrNonWhitelistedFeeCurrency = errors.New("non-whitelisted fee currency") ) var ( @@ -243,7 +243,7 @@ type TxPool struct { queue map[common.Address]*txList // Queued but non-processable transactions beats map[common.Address]time.Time // Last heartbeat from each known account all *txLookup // All transactions to allow lookups - priced *txPricedList // All transactions sorted by price. One heap per gas currency. + priced *txPricedList // All transactions sorted by price. One heap per fee currency. wg sync.WaitGroup // for shutdown sync @@ -625,14 +625,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInvalidSender } - if tx.GasCurrency() != nil && // Non native gas in the tx - !currency.IsWhitelisted(*tx.GasCurrency(), nil, nil) { // The tx currency is not white listed - return ErrNonWhitelistedGasCurrency + // Ensure the fee currency is native or whitelisted. + if tx.FeeCurrency() != nil && !currency.IsWhitelisted(*tx.FeeCurrency(), nil, nil) { + return ErrNonWhitelistedFeeCurrency } // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network - if !local && currency.Cmp(pool.gasPrice, nil, tx.GasPrice(), tx.GasCurrency()) > 0 { + if !local && currency.Cmp(pool.gasPrice, nil, tx.GasPrice(), tx.FeeCurrency()) > 0 { return ErrUnderpriced } // Ensure the transaction adheres to nonce ordering @@ -644,7 +644,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if err != nil { return err } - intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.chain.CurrentBlock().Header(), pool.currentState, tx.GasCurrency()) + intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, pool.chain.CurrentBlock().Header(), pool.currentState, tx.FeeCurrency()) if err != nil { log.Debug("validateTx gas less than intrinsic gas", "intrGas", intrGas, "err", err) return err @@ -654,7 +654,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrIntrinsicGas } - gasPriceMinimum, err := gpm.GetGasPriceMinimum(tx.GasCurrency(), nil, nil) + gasPriceMinimum, err := gpm.GetGasPriceMinimum(tx.FeeCurrency(), nil, nil) if err != nil && err != ccerrors.ErrSmartContractNotDeployed && err != ccerrors.ErrRegistryContractNotDeployed { log.Debug("unable to fetch gas price minimum", "err", err) return err @@ -1199,22 +1199,23 @@ func (pool *TxPool) demoteUnexecutables() { // ValidateTransactorBalanceCoversTx validates transactor has enough funds to cover transaction cost: V + GP * GL. func ValidateTransactorBalanceCoversTx(tx *types.Transaction, from common.Address, currentState *state.StateDB) error { - if tx.GasCurrency() == nil && currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { + if tx.FeeCurrency() == nil && currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { log.Debug("Insufficient funds", "from", from, "Transaction cost", tx.Cost(), "to", tx.To(), "gas", tx.Gas(), "gas price", tx.GasPrice(), "nonce", tx.Nonce(), - "value", tx.Value(), "gas currency", tx.GasCurrency(), "balance", currentState.GetBalance(from)) + "value", tx.Value(), "fee currency", tx.FeeCurrency(), "balance", currentState.GetBalance(from)) return ErrInsufficientFunds - } else if tx.GasCurrency() != nil { - gasCurrencyBalance, _, err := currency.GetBalanceOf(from, *tx.GasCurrency(), params.MaxGasToReadErc20Balance, nil, nil) + } else if tx.FeeCurrency() != nil { + feeCurrencyBalance, _, err := currency.GetBalanceOf(from, *tx.FeeCurrency(), params.MaxGasToReadErc20Balance, nil, nil) if err != nil { - log.Debug("validateTx error in getting gas currency balance", "gasCurrency", tx.GasCurrency(), "error", err) + log.Debug("validateTx error in getting fee currency balance", "feeCurrency", tx.FeeCurrency(), "error", err) return err } - if gasCurrencyBalance.Cmp(new(big.Int).Mul(tx.GasPrice(), big.NewInt(int64(tx.Gas())))) < 0 { - log.Debug("validateTx insufficient gas currency", "gasCurrency", tx.GasCurrency(), "gasCurrencyBalance", gasCurrencyBalance) + gasFee := new(big.Int).Mul(tx.GasPrice(), big.NewInt(int64(tx.Gas()))) + if feeCurrencyBalance.Cmp(new(big.Int).Add(gasFee, tx.GatewayFee())) < 0 { + log.Debug("validateTx insufficient fee currency", "feeCurrency", tx.FeeCurrency(), "feeCurrencyBalance", feeCurrencyBalance) return ErrInsufficientFunds } @@ -1346,10 +1347,10 @@ func (t *txLookup) Add(tx *types.Transaction) { t.lock.Lock() defer t.lock.Unlock() - if tx.GasCurrency() == nil { + if tx.FeeCurrency() == nil { t.nilCurrencyTxCurrCount++ } else { - t.nonNilCurrencyTxCurrCount[*tx.GasCurrency()]++ + t.nonNilCurrencyTxCurrCount[*tx.FeeCurrency()]++ } t.all[tx.Hash()] = tx } @@ -1359,10 +1360,10 @@ func (t *txLookup) Remove(hash common.Hash) { t.lock.Lock() defer t.lock.Unlock() - if t.all[hash].GasCurrency() == nil { + if t.all[hash].FeeCurrency() == nil { t.nilCurrencyTxCurrCount-- } else { - t.nonNilCurrencyTxCurrCount[*t.all[hash].GasCurrency()]-- + t.nonNilCurrencyTxCurrCount[*t.all[hash].FeeCurrency()]-- } delete(t.all, hash) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index e16453257f..eff07d739f 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -88,7 +88,12 @@ func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Tr } func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { - tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil, nil, nil, nil), types.HomesteadSigner{}, key) + return tx +} + +func lesTransaction(nonce uint64, gaslimit uint64, gatewayFee *big.Int, key *ecdsa.PrivateKey) *types.Transaction { + tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil, &common.Address{}, gatewayFee, nil), types.HomesteadSigner{}, key) return tx } @@ -246,6 +251,7 @@ func TestInvalidTransactions(t *testing.T) { tx := transaction(0, 100, key) from, _ := deriveSender(tx) + // Should observe insufficient funds error whne the balance doesn't cover transaction costs. pool.currentState.AddBalance(from, big.NewInt(1)) if err := pool.AddRemote(tx); err != ErrInsufficientFunds { t.Error("expected", ErrInsufficientFunds) @@ -257,6 +263,18 @@ func TestInvalidTransactions(t *testing.T) { t.Error("expected", ErrIntrinsicGas, "got", err) } + // Adding a gateway fee should result in insufficient funds again. + tx = lesTransaction(0, 100, big.NewInt(50), key) + if err := pool.AddRemote(tx); err != ErrInsufficientFunds { + t.Error("expected", ErrInsufficientFunds) + } + + // Should return to intrinsic gas error when gateway fee is covered. + pool.currentState.AddBalance(from, tx.GatewayFee()) + if err := pool.AddRemote(tx); err != ErrIntrinsicGas { + t.Error("expected", ErrIntrinsicGas, "got", err) + } + pool.currentState.SetNonce(from, 1) pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) tx = transaction(0, 100000, key) @@ -334,7 +352,7 @@ func TestTransactionNegativeValue(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil, nil, nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil, nil, nil, nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) pool.currentState.AddBalance(from, big.NewInt(1)) if err := pool.AddRemote(tx); err != ErrNegativeValue { @@ -388,9 +406,9 @@ func TestTransactionDoubleNonce(t *testing.T) { resetState() signer := types.HomesteadSigner{} - tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil, nil, nil), signer, key) - tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil, nil, nil), signer, key) - tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil, nil, nil), signer, key) + tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil, nil, nil, nil), signer, key) + tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil, nil, nil, nil), signer, key) + tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil, nil, nil, nil), signer, key) // Add the first two transaction, ensure higher priced stays only if replace, err := pool.add(tx1, false); err != nil || replace { diff --git a/core/types/block_test.go b/core/types/block_test.go index 7e828415f6..4a9ec0997d 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -28,7 +28,7 @@ import ( // from bcValidBlockTest.json, "SimpleTx" func TestBlockEncoding(t *testing.T) { - blockEnc := common.FromHex("f90264f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ecc60e00b3fe5ce9f6e1a10e5469764daf51f1fe93c22ec3f9a7583a80357217a0d35d334d87c0cc0a202e3756bf81fae08b1575f286c7ee7a3f8df4f0f3afc55da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845c47775c80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000e2e1800a82c350808094095e7baea6a6c7c4c2dfeb977efac326af552d870a80808080c0f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000") + blockEnc := common.FromHex("f90265f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ecc60e00b3fe5ce9f6e1a10e5469764daf51f1fe93c22ec3f9a7583a80357217a0d35d334d87c0cc0a202e3756bf81fae08b1575f286c7ee7a3f8df4f0f3afc55da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845c47775c80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000e3e2800a82c35080808094095e7baea6a6c7c4c2dfeb977efac326af552d870a80808080c0f842a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000") var block Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) @@ -52,7 +52,7 @@ func TestBlockEncoding(t *testing.T) { check("ParentHash", block.ParentHash(), common.HexToHash("7285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7")) check("len(Transactions)", len(block.Transactions()), 1) - check("Transactions[0].Hash", block.Transactions()[0].Hash(), common.HexToHash("613448c2afd5564da95787b6fc1c464f0ef90a63eb5d54eced83e16dbe7c2a1a")) + check("Transactions[0].Hash", block.Transactions()[0].Hash(), common.HexToHash("ef3dcc9051f9e7d1ecb59426f3e5a24b0ad455129eb4525849ca1b0b3d955889")) ourBlockEnc, err := rlp.EncodeToBytes(&block) if err != nil { diff --git a/core/types/transaction.go b/core/types/transaction.go index 65f219f7bf..b9725894a1 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -44,14 +44,15 @@ type Transaction struct { } type txdata struct { - AccountNonce uint64 `json:"nonce" gencodec:"required"` - Price *big.Int `json:"gasPrice" gencodec:"required"` - GasLimit uint64 `json:"gas" gencodec:"required"` - GasCurrency *common.Address `json:"gasCurrency" rlp:"nil"` // nil means native currency - GasFeeRecipient *common.Address `json:"gasFeeRecipient" rlp:"nil"` // nil means no fees are paid - Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation - Amount *big.Int `json:"value" gencodec:"required"` - Payload []byte `json:"input" gencodec:"required"` + AccountNonce uint64 `json:"nonce" gencodec:"required"` + Price *big.Int `json:"gasPrice" gencodec:"required"` + GasLimit uint64 `json:"gas" gencodec:"required"` + FeeCurrency *common.Address `json:"feeCurrency" rlp:"nil"` // nil means native currency + GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient" rlp:"nil"` // nil means no gateway fee is paid + GatewayFee *big.Int `json:"gatewayFee" rlp:"nil"` // nil means no gateway fee is paid + Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation + Amount *big.Int `json:"value" gencodec:"required"` + Payload []byte `json:"input" gencodec:"required"` // Signature values V *big.Int `json:"v" gencodec:"required"` @@ -63,46 +64,51 @@ type txdata struct { } type txdataMarshaling struct { - AccountNonce hexutil.Uint64 - Price *hexutil.Big - GasLimit hexutil.Uint64 - GasCurrency *hexutil.Big - GasFeeRecipient *hexutil.Big - Amount *hexutil.Big - Payload hexutil.Bytes - V *hexutil.Big - R *hexutil.Big - S *hexutil.Big + AccountNonce hexutil.Uint64 + Price *hexutil.Big + GasLimit hexutil.Uint64 + FeeCurrency *hexutil.Big + GatewayFeeRecipient *hexutil.Big + GatewayFee *hexutil.Big + Amount *hexutil.Big + Payload hexutil.Bytes + V *hexutil.Big + R *hexutil.Big + S *hexutil.Big } -func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, gasCurrency, gasFeeRecipient *common.Address, data []byte) *Transaction { - return newTransaction(nonce, &to, amount, gasLimit, gasPrice, gasCurrency, gasFeeRecipient, data) +func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, feeCurrency, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, data []byte) *Transaction { + return newTransaction(nonce, &to, amount, gasLimit, gasPrice, feeCurrency, gatewayFeeRecipient, gatewayFee, data) } -func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, gasCurrency, gasFeeRecipient *common.Address, data []byte) *Transaction { - return newTransaction(nonce, nil, amount, gasLimit, gasPrice, gasCurrency, gasFeeRecipient, data) +func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, feeCurrency, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, data []byte) *Transaction { + return newTransaction(nonce, nil, amount, gasLimit, gasPrice, feeCurrency, gatewayFeeRecipient, gatewayFee, data) } -func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, gasCurrency, gasFeeRecipient *common.Address, data []byte) *Transaction { +func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, feeCurrency, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, data []byte) *Transaction { if len(data) > 0 { data = common.CopyBytes(data) } d := txdata{ - AccountNonce: nonce, - Recipient: to, - Payload: data, - Amount: new(big.Int), - GasLimit: gasLimit, - GasCurrency: gasCurrency, - GasFeeRecipient: gasFeeRecipient, - Price: new(big.Int), - V: new(big.Int), - R: new(big.Int), - S: new(big.Int), + AccountNonce: nonce, + Recipient: to, + Payload: data, + Amount: new(big.Int), + GasLimit: gasLimit, + FeeCurrency: feeCurrency, + GatewayFeeRecipient: gatewayFeeRecipient, + GatewayFee: new(big.Int), + Price: new(big.Int), + V: new(big.Int), + R: new(big.Int), + S: new(big.Int), } if amount != nil { d.Amount.Set(amount) } + if gatewayFee != nil { + d.GatewayFee.Set(gatewayFee) + } if gasPrice != nil { d.Price.Set(gasPrice) } @@ -178,14 +184,15 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return nil } -func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } -func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } -func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } -func (tx *Transaction) GasCurrency() *common.Address { return tx.data.GasCurrency } -func (tx *Transaction) GasFeeRecipient() *common.Address { return tx.data.GasFeeRecipient } -func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } -func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } -func (tx *Transaction) CheckNonce() bool { return true } +func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } +func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } +func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } +func (tx *Transaction) FeeCurrency() *common.Address { return tx.data.FeeCurrency } +func (tx *Transaction) GatewayFeeRecipient() *common.Address { return tx.data.GatewayFeeRecipient } +func (tx *Transaction) GatewayFee() *big.Int { return tx.data.GatewayFee } +func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } +func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } +func (tx *Transaction) CheckNonce() bool { return true } // To returns the recipient address of the transaction. // It returns nil if the transaction is a contract creation. @@ -227,15 +234,16 @@ func (tx *Transaction) Size() common.StorageSize { // XXX Rename message to something less arbitrary? func (tx *Transaction) AsMessage(s Signer) (Message, error) { msg := Message{ - nonce: tx.data.AccountNonce, - gasLimit: tx.data.GasLimit, - gasPrice: new(big.Int).Set(tx.data.Price), - gasCurrency: tx.data.GasCurrency, - gasFeeRecipient: tx.data.GasFeeRecipient, - to: tx.data.Recipient, - amount: tx.data.Amount, - data: tx.data.Payload, - checkNonce: true, + nonce: tx.data.AccountNonce, + gasLimit: tx.data.GasLimit, + gasPrice: new(big.Int).Set(tx.data.Price), + feeCurrency: tx.data.FeeCurrency, + gatewayFeeRecipient: tx.data.GatewayFeeRecipient, + gatewayFee: tx.data.GatewayFee, + to: tx.data.Recipient, + amount: tx.data.Amount, + data: tx.data.Payload, + checkNonce: true, } var err error @@ -255,10 +263,11 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e return cpy, nil } -// Cost returns amount + gasprice * gaslimit. +// Cost returns amount + gasprice * gaslimit + gatewayfee. func (tx *Transaction) Cost() *big.Int { total := new(big.Int).Mul(tx.data.Price, new(big.Int).SetUint64(tx.data.GasLimit)) total.Add(total, tx.data.Amount) + total.Add(total, tx.data.GatewayFee) return total } @@ -410,40 +419,43 @@ func (t *TransactionsByPriceAndNonce) Pop() { // // NOTE: In a future PR this will be removed. type Message struct { - to *common.Address - from common.Address - nonce uint64 - amount *big.Int - gasLimit uint64 - gasPrice *big.Int - gasCurrency *common.Address - gasFeeRecipient *common.Address - data []byte - checkNonce bool -} - -func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, gasCurrency, gasFeeRecipient *common.Address, data []byte, checkNonce bool) Message { + to *common.Address + from common.Address + nonce uint64 + amount *big.Int + gasLimit uint64 + gasPrice *big.Int + feeCurrency *common.Address + gatewayFeeRecipient *common.Address + gatewayFee *big.Int + data []byte + checkNonce bool +} + +func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, feeCurrency, gatewayFeeRecipient *common.Address, gatewayFee *big.Int, data []byte, checkNonce bool) Message { return Message{ - from: from, - to: to, - nonce: nonce, - amount: amount, - gasLimit: gasLimit, - gasPrice: gasPrice, - gasCurrency: gasCurrency, - gasFeeRecipient: gasFeeRecipient, - data: data, - checkNonce: checkNonce, + from: from, + to: to, + nonce: nonce, + amount: amount, + gasLimit: gasLimit, + gasPrice: gasPrice, + feeCurrency: feeCurrency, + gatewayFeeRecipient: gatewayFeeRecipient, + gatewayFee: gatewayFee, + data: data, + checkNonce: checkNonce, } } -func (m Message) From() common.Address { return m.from } -func (m Message) To() *common.Address { return m.to } -func (m Message) GasPrice() *big.Int { return m.gasPrice } -func (m Message) GasCurrency() *common.Address { return m.gasCurrency } -func (m Message) GasFeeRecipient() *common.Address { return m.gasFeeRecipient } -func (m Message) Value() *big.Int { return m.amount } -func (m Message) Gas() uint64 { return m.gasLimit } -func (m Message) Nonce() uint64 { return m.nonce } -func (m Message) Data() []byte { return m.data } -func (m Message) CheckNonce() bool { return m.checkNonce } +func (m Message) From() common.Address { return m.from } +func (m Message) To() *common.Address { return m.to } +func (m Message) GasPrice() *big.Int { return m.gasPrice } +func (m Message) FeeCurrency() *common.Address { return m.feeCurrency } +func (m Message) GatewayFeeRecipient() *common.Address { return m.gatewayFeeRecipient } +func (m Message) GatewayFee() *big.Int { return m.gatewayFee } +func (m Message) Value() *big.Int { return m.amount } +func (m Message) Gas() uint64 { return m.gasLimit } +func (m Message) Nonce() uint64 { return m.nonce } +func (m Message) Data() []byte { return m.data } +func (m Message) CheckNonce() bool { return m.checkNonce } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 1a8e2aa7f9..3526649c18 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -157,8 +157,9 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash { tx.data.AccountNonce, tx.data.Price, tx.data.GasLimit, - tx.data.GasCurrency, - tx.data.GasFeeRecipient, + tx.data.FeeCurrency, + tx.data.GatewayFeeRecipient, + tx.data.GatewayFee, tx.data.Recipient, tx.data.Amount, tx.data.Payload, @@ -211,8 +212,9 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash { tx.data.AccountNonce, tx.data.Price, tx.data.GasLimit, - tx.data.GasCurrency, - tx.data.GasFeeRecipient, + tx.data.FeeCurrency, + tx.data.GatewayFeeRecipient, + tx.data.GatewayFee, tx.data.Recipient, tx.data.Amount, tx.data.Payload, diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index 32325e1ef9..4e40662ee6 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, nil), signer, key) if err != nil { t.Fatal(err) } @@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, nil), signer, key) if err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ func TestEIP155ChainId(t *testing.T) { t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId()) } - tx = NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil) + tx = NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil, nil, nil, nil) tx, err = SignTx(tx, HomesteadSigner{}, key) if err != nil { t.Fatal(err) @@ -81,11 +81,11 @@ func TestEIP155SigningVitalik(t *testing.T) { for i, test := range []struct { txRlp, addr string }{ - {"f866808398968082a4108080943535353535353535353535353535353535353535018255441ba05e13b77d1ca6cab8f479a0f979e0bc2556ce17b306c832fb2b9313e57021c75ba02302d57566abf5a33ae7691b9751f5e70585260bea55b8cd5184192342372d7a", "0xf87a4defd9fb983855996d1a7fed5b02af98d9cc"}, - {"f867018401312d008252088080943535353535353535353535353535353535353535018255441ba02a15ff927052f41cb41d8f8622564ba726abbd8a8e15994e87d6e33dc0e2aa03a02f77057ad12f763f5cc1200b105056a45e5c90413fc3641de56b02d36d533dc5", "0x6935890fef53eda8184fb4b41e3c1afc66bde460"}, - {"f87b0a8402625a00826d60809435353735353535353535353535353535353535359435353735353535353535353535353535353535350a8255441ba05547015b5fedaa3a9b37b2c456369e0a031578df6f84863babe6a45af9357ecaa02144e0ffa81eff11ed857503423c77f8b44f85bfa532b8160efb4ec40b4cfe01", "0x46ac6444292d6e397ad5e233cec345b979ab2d4e"}, - {"f87b0a8402625a00826d60809435353735353535353535353535353535353535359435353735353535353535353535353535353535350a8255741ba03b08a1ba373e618447ea87e8f16b60600fdfc3e3a145f147cded36ed67fb08eda02414c92fd86494343b2e24c6e5b14c10f216fc68d1f37ddfc8ea7e0fed7bb2ab", "0xb5c28cc71edcae4b8887f9742c82ae7470b6fbc3"}, - {"f87b0a8402625a00826d60809435353735353535353535353535353535353535a59435353735353535353535353535353535353535350a8255741ca00d1dd55bd93b85484812c37fee292e36166cef2a979f19a794b48ffb254b8e6ba07ac6fbb7918b7a0112238eeb52858974ad5df3ca30cada2f40ddcabab69e66ed", "0x32587123ba45edd5e5d981dd0d0983d25c5876a2"}, + {"f867808398968082a410808080943535353535353535353535353535353535353535018255441ba05e13b77d1ca6cab8f479a0f979e0bc2556ce17b306c832fb2b9313e57021c75ba02302d57566abf5a33ae7691b9751f5e70585260bea55b8cd5184192342372d7a", "0xb37b36527046ca6791276c205429eb1c4feb562e"}, + {"f868018401312d00825208808080943535353535353535353535353535353535353535018255441ba02a15ff927052f41cb41d8f8622564ba726abbd8a8e15994e87d6e33dc0e2aa03a02f77057ad12f763f5cc1200b105056a45e5c90413fc3641de56b02d36d533dc5", "0x2b7f6efbfa37b5233104da0f9f2ab7fc9e0a1ad1"}, + {"f87e0a8402625a00826d6080943535373535353535353535353535353535353535824e209435353735353535353535353535353535353535350a8255441ba05547015b5fedaa3a9b37b2c456369e0a031578df6f84863babe6a45af9357ecaa02144e0ffa81eff11ed857503423c77f8b44f85bfa532b8160efb4ec40b4cfe01", "0xb8691d7283eb5b3aa7b9b80633392d30992f1b47"}, + {"f87e0a8402625a00826d6080943535373535353535353535353535353535353535824e209435353735353535353535353535353535353535350a8255741ba03b08a1ba373e618447ea87e8f16b60600fdfc3e3a145f147cded36ed67fb08eda02414c92fd86494343b2e24c6e5b14c10f216fc68d1f37ddfc8ea7e0fed7bb2ab", "0x3155b94fa4129ea44a01990998a9815bb81bc535"}, + {"f87e0a8402625a00826d60809435353735353535353535353535353535353535a5824e209435353735353535353535353535353535353535350a8255741ca00d1dd55bd93b85484812c37fee292e36166cef2a979f19a794b48ffb254b8e6ba07ac6fbb7918b7a0112238eeb52858974ad5df3ca30cada2f40ddcabab69e66ed", "0x058e690781d4300a0bc29911f2a605474e4f96b7"}, } { signer := NewEIP155Signer(big.NewInt(1)) @@ -113,7 +113,7 @@ func TestEIP155SigningVitalik(t *testing.T) { func TestChainId(t *testing.T) { key, _ := defaultTestKey() - tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil) + tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil, nil, nil, nil) var err error tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key) diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 224bc6eb7d..468117702e 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -38,6 +38,7 @@ var ( nil, nil, nil, + nil, ) rightvrsTx, _ = NewTransaction( @@ -48,6 +49,7 @@ var ( big.NewInt(1), nil, nil, + nil, common.FromHex("5544"), ).WithSignature( HomesteadSigner{}, @@ -57,10 +59,10 @@ var ( func TestTransactionSigHash(t *testing.T) { var homestead HomesteadSigner - if homestead.Hash(emptyTx) != common.HexToHash("fb81b18a3eb793dfd8e02d08613259b548ab2da940434a96737c738269e29080") { + if homestead.Hash(emptyTx) != common.HexToHash("0884127f4e682c55978e9e8a4cecc734bf3fa14776a3c2b28adc16855cb3a491") { t.Errorf("empty transaction hash mismatch, got %x", homestead.Hash(emptyTx)) } - if homestead.Hash(rightvrsTx) != common.HexToHash("05be82cd19ecd9018a33db2ef586bf68cf7731dd36591e8f77e67095ea1884d1") { + if homestead.Hash(rightvrsTx) != common.HexToHash("b879218b07bdecfa13fbfcca8ea298aab32d06e5ecd7b021a51b53c5f8919209") { t.Errorf("RightVRS transaction hash mismatch, got %x", homestead.Hash(rightvrsTx)) } } @@ -70,7 +72,7 @@ func TestTransactionEncode(t *testing.T) { if err != nil { t.Fatalf("encode error: %v", err) } - should := common.FromHex("f86303018207d0808094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a8255441ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3") + should := common.FromHex("f86403018207d080808094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a8255441ca098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa08887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3") if !bytes.Equal(txb, should) { t.Errorf("encoded RLP mismatch, got %x", txb) } @@ -165,9 +167,7 @@ func TestTxAmountChanged(t *testing.T) { } } -// Tests that a modified transaction does not produce a valid signature - -func TestTxGasFeeRecipientChanged(t *testing.T) { +func TestTxGatewayFeeRecipientChanged(t *testing.T) { _, addr := defaultTestKey() tx, err := decodeTx(signAndEncodeTx(rightvrsTx)) @@ -177,7 +177,29 @@ func TestTxGasFeeRecipientChanged(t *testing.T) { } recipientAddr := common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b") - tx.data.GasFeeRecipient = &recipientAddr + tx.data.GatewayFeeRecipient = &recipientAddr + + from, err := Sender(HomesteadSigner{}, tx) + if err != nil { + t.Error(err) + t.FailNow() + } + + if addr == from { + t.Error("derived address shouldn't match") + } +} + +func TestTxGatewayFee(t *testing.T) { + _, addr := defaultTestKey() + + tx, err := decodeTx(signAndEncodeTx(rightvrsTx)) + if err != nil { + t.Error(err) + t.FailNow() + } + + tx.data.GatewayFee.SetInt64(5) from, err := Sender(HomesteadSigner{}, tx) if err != nil { @@ -206,7 +228,7 @@ func TestTransactionPriceNonceSort(t *testing.T) { for start, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for i := 0; i < 25; i++ { - tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil, nil, nil), signer, key) + tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil, nil, nil, nil), signer, key) groups[addr] = append(groups[addr], tx) } } @@ -257,9 +279,9 @@ func TestTransactionJSON(t *testing.T) { var tx *Transaction switch i % 2 { case 0: - tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, nil, nil, []byte("abcdef")) + tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, nil, nil, nil, []byte("abcdef")) case 1: - tx = NewContractCreation(i, common.Big0, 1, common.Big2, nil, nil, []byte("abcdef")) + tx = NewContractCreation(i, common.Big0, 1, common.Big2, nil, nil, nil, []byte("abcdef")) } transactions = append(transactions, tx) diff --git a/eth/api_backend.go b/eth/api_backend.go index ec5bb549f3..6984fd1e87 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -227,6 +227,10 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma } } -func (b *EthAPIBackend) GasFeeRecipient() common.Address { - return b.eth.GasFeeRecipient() +func (b *EthAPIBackend) GatewayFeeRecipient() common.Address { + return b.eth.GatewayFeeRecipient() +} + +func (b *EthAPIBackend) GatewayFee() *big.Int { + return b.eth.GatewayFee() } diff --git a/eth/backend.go b/eth/backend.go index 87a2f02e28..9e718d468b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -86,10 +86,11 @@ type Ethereum struct { APIBackend *EthAPIBackend - miner *miner.Miner - gasPrice *big.Int - etherbase common.Address - blsbase common.Address + miner *miner.Miner + gasPrice *big.Int + gatewayFee *big.Int + etherbase common.Address + blsbase common.Address networkID uint64 netRPCService *ethapi.PublicNetAPI @@ -116,6 +117,10 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice) config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice) } + if config.GatewayFee == nil || config.GatewayFee.Cmp(common.Big0) <= 0 { + log.Warn("Sanitizing invalid gateway fee", "provided", config.GatewayFee, "updated", DefaultConfig.GatewayFee) + config.GatewayFee = new(big.Int).Set(DefaultConfig.GatewayFee) + } // Assemble the Ethereum object chainDb, err := CreateDB(ctx, config, "chaindata") if err != nil { @@ -138,6 +143,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { shutdownChan: make(chan bool), networkID: config.NetworkId, gasPrice: config.MinerGasPrice, + gatewayFee: config.GatewayFee, etherbase: config.Etherbase, blsbase: config.BLSbase, bloomRequests: make(chan chan *bloombits.Retrieval), @@ -528,18 +534,19 @@ func (s *Ethereum) StopMining() { func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } -func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } -func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } -func (s *Ethereum) Config() *Config { return s.config } -func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } -func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } -func (s *Ethereum) Engine() consensus.Engine { return s.engine } -func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } -func (s *Ethereum) IsListening() bool { return true } // Always listening -func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } -func (s *Ethereum) NetVersion() uint64 { return s.networkID } -func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } -func (s *Ethereum) GasFeeRecipient() common.Address { return s.config.Etherbase } +func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } +func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } +func (s *Ethereum) Config() *Config { return s.config } +func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } +func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } +func (s *Ethereum) Engine() consensus.Engine { return s.engine } +func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } +func (s *Ethereum) IsListening() bool { return true } // Always listening +func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } +func (s *Ethereum) NetVersion() uint64 { return s.networkID } +func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } +func (s *Ethereum) GatewayFeeRecipient() common.Address { return common.Address{} } // Full-nodes do not make use of gateway fee. +func (s *Ethereum) GatewayFee() *big.Int { return common.Big0 } // Protocols implements node.Service, returning all the currently configured // network protocols to start. diff --git a/eth/config.go b/eth/config.go index f4d6c9584d..6b1325f27f 100644 --- a/eth/config.go +++ b/eth/config.go @@ -51,6 +51,7 @@ var DefaultConfig = Config{ MinerGasCeil: 8000000, MinerGasPrice: big.NewInt(1), MinerRecommit: 3 * time.Second, + GatewayFee: big.NewInt(10000), TxPool: core.DefaultTxPoolConfig, @@ -89,7 +90,9 @@ type Config struct { // Light client options LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests LightPeers int `toml:",omitempty"` // Maximum number of LES client peers - // The GasFeeRecipient light clients need to specify in order for their transactions to be accepted by this node. + // Minimum gateway fee value to serve a transaction from a light client + GatewayFee *big.Int `toml:",omitempty"` + // Etherbase is the GatewayFeeRecipient light clients need to specify in order for their transactions to be accepted by this node. // Also the coinbase used for mining. Etherbase common.Address `toml:",omitempty"` BLSbase common.Address `toml:",omitempty"` diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go index 3b4798e48d..f77e1ee6ec 100644 --- a/eth/downloader/testchain_test.go +++ b/eth/downloader/testchain_test.go @@ -127,7 +127,7 @@ func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) // Include transactions to the miner to make blocks more interesting. if parent == tc.genesis && i%22 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index 53a13e58c8..c01aa0fe30 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -52,7 +52,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 85d7e2c437..e2e90736f3 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -227,11 +227,11 @@ func TestPendingTxFilter(t *testing.T) { api = NewPublicFilterAPI(backend, false) transactions = []*types.Transaction{ - types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), - types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil), + types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, nil), + types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, nil), + types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, nil), + types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, nil), + types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil, nil, nil, nil), } hashes []common.Hash diff --git a/eth/handler_test.go b/eth/handler_test.go index 032e5b9a01..56bb3c2248 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -315,13 +315,13 @@ func testGetNodeData(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -407,13 +407,13 @@ func testGetReceipt(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/eth/helper_test.go b/eth/helper_test.go index f6155cd81e..2105a312cd 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -129,7 +129,7 @@ func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subs // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { - tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil, nil, make([]byte, datasize)) + tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil, nil, nil, make([]byte, datasize)) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) return tx } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index ed26a6eaef..9b0c2c0130 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -116,7 +116,7 @@ type callTracerTest struct { func TestPrestateTracerCreate2(t *testing.T) { unsigned_tx := types.NewTransaction(1, common.HexToAddress("0x00000000000000000000000000000000deadbeef"), - new(big.Int), 5000000, big.NewInt(1), nil, nil, []byte{}) + new(big.Int), 5000000, big.NewInt(1), nil, nil, nil, []byte{}) privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) if err != nil { diff --git a/interfaces.go b/interfaces.go index b0f22d6cd4..cdfa58b90e 100644 --- a/interfaces.go +++ b/interfaces.go @@ -113,14 +113,15 @@ type ChainSyncReader interface { // CallMsg contains parameters for contract calls. type CallMsg struct { - From common.Address // the sender of the 'transaction' - To *common.Address // the destination contract (nil for contract creation) - Gas uint64 // if 0, the call executes with near-infinite gas - GasCurrency *common.Address // 0 for the native currency - GasFeeRecipient *common.Address // 0 for returning gas fees to the sender - GasPrice *big.Int // wei <-> gas exchange ratio - Value *big.Int // amount of wei sent along with the call - Data []byte // input data, usually an ABI-encoded contract method invocation + From common.Address // the sender of the 'transaction' + 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 + GatewayFeeRecipient *common.Address // 0 for no gateway fee + GatewayFee *big.Int // 0 for no gateway fee + GasPrice *big.Int // wei <-> gas exchange ratio + Value *big.Int // amount of wei sent along with the call + Data []byte // input data, usually an ABI-encoded contract method invocation } // A ContractCaller provides contract calls, essentially transactions that are executed by diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e44ca339da..0e1551e410 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -672,14 +672,15 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A // CallArgs represents the arguments for a call. type CallArgs struct { - From common.Address `json:"from"` - To *common.Address `json:"to"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice hexutil.Big `json:"gasPrice"` - GasCurrency *common.Address `json:"gasCurrency"` - GasFeeRecipient *common.Address `json:"gasFeeRecipient"` - Value hexutil.Big `json:"value"` - Data hexutil.Bytes `json:"data"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice hexutil.Big `json:"gasPrice"` + FeeCurrency *common.Address `json:"feeCurrency"` + GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient"` + GatewayFee hexutil.Big `json:"gatewayFee"` + Value hexutil.Big `json:"value"` + Data hexutil.Bytes `json:"data"` } func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration) ([]byte, uint64, bool, error) { @@ -707,11 +708,11 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // which will always be in Gold. This allows the default price to be set for the proper currency. // TODO(asa): Remove this once this is handled in the Provider. if gasPrice.Sign() == 0 || gasPrice.Cmp(big.NewInt(0)) == 0 { - gasPrice, err = s.b.SuggestPriceInCurrency(ctx, args.GasCurrency) + gasPrice, err = s.b.SuggestPriceInCurrency(ctx, args.FeeCurrency) } // Create new call message - msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.GasCurrency, args.GasFeeRecipient, args.Data, false) + msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.FeeCurrency, args.GatewayFeeRecipient, args.GatewayFee.ToInt(), args.Data, false) // Setup context so it may be cancelled the call has completed // or, in case of unmetered gas, setup a context with a timeout. @@ -938,22 +939,23 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction type RPCTransaction struct { - BlockHash common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasCurrency *common.Address `json:"gasCurrency"` - GasFeeRecipient *common.Address `json:"gasFeeRecipient"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex hexutil.Uint `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` + BlockHash common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + FeeCurrency *common.Address `json:"feeCurrency"` + GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient"` + GatewayFee *hexutil.Big `json:"gatewayFee"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex hexutil.Uint `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` } // newRPCTransaction returns a transaction that will serialize to the RPC @@ -967,19 +969,20 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber v, r, s := tx.RawSignatureValues() result := &RPCTransaction{ - From: from, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - GasCurrency: tx.GasCurrency(), - GasFeeRecipient: tx.GasFeeRecipient(), - Hash: tx.Hash(), - Input: hexutil.Bytes(tx.Data()), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - V: (*hexutil.Big)(v), - R: (*hexutil.Big)(r), - S: (*hexutil.Big)(s), + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + FeeCurrency: tx.FeeCurrency(), + GatewayFeeRecipient: tx.GatewayFeeRecipient(), + GatewayFee: (*hexutil.Big)(tx.GatewayFee()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), } if blockHash != (common.Hash{}) { result.BlockHash = blockHash @@ -1202,14 +1205,15 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti // SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool. type SendTxArgs struct { - From common.Address `json:"from"` - To *common.Address `json:"to"` - Gas *hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasCurrency *common.Address `json:"gasCurrency"` - GasFeeRecipient *common.Address `json:"gasFeeRecipient"` - Value *hexutil.Big `json:"value"` - Nonce *hexutil.Uint64 `json:"nonce"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + FeeCurrency *common.Address `json:"feeCurrency"` + GatewayFeeRecipient *common.Address `json:"gatewayFeeRecipient"` + GatewayFee *hexutil.Big `json:"gatewayFee"` + Value *hexutil.Big `json:"value"` + Nonce *hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. "input" is the // newer name and should be preferred by clients. Data *hexutil.Bytes `json:"data"` @@ -1221,17 +1225,17 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { args.Gas = new(hexutil.Uint64) defaultGas := uint64(90000) - if args.GasCurrency == nil { + if args.FeeCurrency == nil { *(*uint64)(args.Gas) = defaultGas } else { - // When paying for gas in a currency other than Celo Gold, the intrinsic gas use is greater than when paying for gas in Celo Gold. + // When paying for fees in a currency other than Celo Gold, the intrinsic gas use is greater than when paying for fees in Celo Gold. // We need to cover the gas use of one 'balanceOf', one 'debitFrom', and two 'creditTo' calls. state, header, err := b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber) if err != nil { - *(*uint64)(args.Gas) = defaultGas + blockchain_parameters.GetIntrinsicGasForAlternativeGasCurrency(header, state) + *(*uint64)(args.Gas) = defaultGas + blockchain_parameters.GetIntrinsicGasForAlternativeFeeCurrency(header, state) } else { - log.Warn("Cannot read intrinsic gas for alternative gas currency", "err", err) - *(*uint64)(args.Gas) = defaultGas + params.IntrinsicGasForAlternativeGasCurrency + log.Warn("Cannot read intrinsic gas for alternative fee currency", "err", err) + *(*uint64)(args.Gas) = defaultGas + params.IntrinsicGasForAlternativeFeeCurrency } } } @@ -1239,7 +1243,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { // which will always be in Gold. This allows the default price to be set for the proper currency. // TODO(asa): Remove this once this is handled in the Provider. if args.GasPrice == nil || args.GasPrice.ToInt().Cmp(big.NewInt(0)) == 0 { - price, err := b.SuggestPriceInCurrency(ctx, args.GasCurrency) + price, err := b.SuggestPriceInCurrency(ctx, args.FeeCurrency) if err != nil { return err } @@ -1271,12 +1275,16 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { } } - if args.GasFeeRecipient == nil { - recipient := b.GasFeeRecipient() + if args.GatewayFeeRecipient == nil { + recipient := b.GatewayFeeRecipient() if (recipient != common.Address{}) { - args.GasFeeRecipient = &recipient + args.GatewayFeeRecipient = &recipient } } + + if args.GatewayFeeRecipient != nil && args.GatewayFee == nil { + args.GatewayFee = (*hexutil.Big)(b.GatewayFee()) + } return nil } @@ -1288,9 +1296,9 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { input = *args.Input } if args.To == nil { - return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), args.GasCurrency, args.GasFeeRecipient, input) + return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), args.FeeCurrency, args.GatewayFeeRecipient, (*big.Int)(args.GatewayFee), input) } - return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), args.GasCurrency, args.GasFeeRecipient, input) + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), args.FeeCurrency, args.GatewayFeeRecipient, (*big.Int)(args.GatewayFee), input) } // submitTransaction is a helper function that submits tx to txPool and logs a message. diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 5e333e8c0d..30a647040c 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -71,7 +71,8 @@ type Backend interface { ChainConfig() *params.ChainConfig CurrentBlock() *types.Block - GasFeeRecipient() common.Address + GatewayFeeRecipient() common.Address + GatewayFee() *big.Int } func GetAPIs(apiBackend Backend) []rpc.API { diff --git a/les/api_backend.go b/les/api_backend.go index f9b589c1d2..c8260cd75d 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -209,6 +210,11 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma } } -func (b *LesApiBackend) GasFeeRecipient() common.Address { +func (b *LesApiBackend) GatewayFeeRecipient() common.Address { return b.eth.GetRandomPeerEtherbase() } + +func (b *LesApiBackend) GatewayFee() *big.Int { + // TODO(nategraf): Create a method to fetch the gateway fee values of peers along with the coinbase. + return eth.DefaultConfig.GatewayFee +} diff --git a/les/backend.go b/les/backend.go index 6ed3fbb48e..96c828891c 100644 --- a/les/backend.go +++ b/les/backend.go @@ -159,7 +159,13 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { } leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) - if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, light.DefaultClientIndexerConfig, syncMode, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, leth.serverPool, quitSync, &leth.wg, config.Etherbase); err != nil { + leth.protocolManager, err = NewProtocolManager( + leth.chainConfig, light.DefaultClientIndexerConfig, syncMode, + config.NetworkId, leth.eventMux, leth.engine, leth.peers, + leth.blockchain, nil, chainDb, leth.odr, leth.relay, + leth.serverPool, quitSync, &leth.wg, config.Etherbase, config.GatewayFee, + ) + if err != nil { return nil, err } leth.ApiBackend = &LesApiBackend{leth} diff --git a/les/handler.go b/les/handler.go index 165ae13826..b6dfb72e05 100644 --- a/les/handler.go +++ b/les/handler.go @@ -105,6 +105,7 @@ type ProtocolManager struct { reqDist *requestDistributor retriever *retrieveManager etherbase common.Address + gatewayFee *big.Int downloader *downloader.Downloader fetcher *lightFetcher @@ -129,7 +130,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In syncMode downloader.SyncMode, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, serverPool *serverPool, quitSync chan struct{}, - wg *sync.WaitGroup, etherbase common.Address) (*ProtocolManager, error) { + wg *sync.WaitGroup, etherbase common.Address, gatewayFee *big.Int) (*ProtocolManager, error) { lightSync := !syncMode.SyncFullBlockChain() // Create the protocol manager with the base fields manager := &ProtocolManager{ @@ -150,6 +151,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In wg: wg, noMorePeers: make(chan struct{}), etherbase: etherbase, + gatewayFee: gatewayFee, } if odr != nil { manager.retriever = odr.retriever @@ -361,15 +363,25 @@ func (pm *ProtocolManager) handle(p *peer) error { var reqList = []uint64{GetBlockHeadersMsg, GetBlockBodiesMsg, GetCodeMsg, GetReceiptsMsg, GetProofsV1Msg, SendTxMsg, SendTxV2Msg, GetTxStatusMsg, GetHeaderProofsMsg, GetProofsV2Msg, GetHelperTrieProofsMsg, GetEtherbaseMsg} -func (pm *ProtocolManager) verifyGasFeeRecipient(gasFeeRecipient *common.Address) bool { - // If this node does not specify an etherbase, accept any GasFeeRecipient. Otherwise, +func (pm *ProtocolManager) verifyGatewayFee(gatewayFeeRecipient *common.Address, gatewayFee *big.Int) error { + // If this node does not specify an etherbase, accept any GatewayFeeRecipient. Otherwise, // reject transactions that don't pay gas fees to this node. if (pm.etherbase != common.Address{}) { - if gasFeeRecipient == nil || *gasFeeRecipient != pm.etherbase { - return false + if gatewayFeeRecipient == nil { + return fmt.Errorf("gateway fee recipient must be %s, got ", pm.etherbase.String()) + } + if *gatewayFeeRecipient != pm.etherbase { + return fmt.Errorf("gateway fee recipient must be %s, got %s", pm.etherbase.String(), (*gatewayFeeRecipient).String()) + } + + // Check that the value of the supplied gateway fee is at least the minimum. + if pm.gatewayFee != nil && pm.gatewayFee.Cmp(common.Big0) > 0 { + if gatewayFee == nil || gatewayFee.Cmp(pm.gatewayFee) < 0 { + return fmt.Errorf("gateway fee value must be at least %s, got %s", pm.gatewayFee, gatewayFee) + } } } - return true + return nil } // handleMsg is invoked whenever an inbound message is received from a remote @@ -1068,8 +1080,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrRequestRejected, "") } for _, tx := range txs { - if !pm.verifyGasFeeRecipient(tx.GasFeeRecipient()) { - return errResp(ErrRequestRejected, "Invalid GasFeeRecipient") + if err := pm.verifyGatewayFee(tx.GatewayFeeRecipient(), tx.GatewayFee()); err != nil { + return errResp(ErrRequestRejected, "tx %v: %v", tx, err) } } pm.txpool.AddRemotes(txs) @@ -1102,11 +1114,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { for i, stat := range stats { if stat.Status == core.TxStatusUnknown { tx := req.Txs[i] - if !pm.verifyGasFeeRecipient(tx.GasFeeRecipient()) { - stats[i].Error = fmt.Sprintf("Invalid GasFeeRecipient for node with etherbase %v, got %v", pm.etherbase, tx.GasFeeRecipient()) + if err := pm.verifyGatewayFee(tx.GatewayFeeRecipient(), tx.GatewayFee()); err != nil { + stats[i].Error = err.Error() continue } - if errs := pm.txpool.AddRemotes([]*types.Transaction{tx}); errs[0] != nil { stats[i].Error = errs[0].Error() continue diff --git a/les/handler_test.go b/les/handler_test.go index 75a7fbee36..6d9b39f2c8 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -525,13 +525,13 @@ func TestTransactionStatusLes2(t *testing.T) { // tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil), signer, testBankKey) // test(tx0, true, txStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()}) - tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, nil), signer, testBankKey) test(tx1, false, txStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown test(tx1, true, txStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending test(tx1, true, txStatus{Status: core.TxStatusPending}) // adding it again should not return an error - tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, testBankKey) - tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, nil), signer, testBankKey) + tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, nil), signer, testBankKey) // send transactions in the wrong order, tx3 should be queued test(tx3, true, txStatus{Status: core.TxStatusQueued}) test(tx2, true, txStatus{Status: core.TxStatusPending}) @@ -581,3 +581,62 @@ func TestTransactionStatusLes2(t *testing.T) { test(tx1, false, txStatus{Status: core.TxStatusPending}) test(tx2, false, txStatus{Status: core.TxStatusPending}) } + +func TestTransactionGatewayFeeRequirementLes2(t *testing.T) { + db := ethdb.NewMemDatabase() + pm := newTestProtocolManagerMust(t, downloader.FullSync, 0, nil, nil, nil, db) + pm.etherbase = common.HexToAddress("2ad937cb878d8beefc84f3d0545750c2ff78cd0e") + pm.gatewayFee = big.NewInt(25000) + chain := pm.blockchain.(*core.BlockChain) + config := core.DefaultTxPoolConfig + config.Journal = "" + txpool := core.NewTxPool(config, params.TestChainConfig, chain) + pm.txpool = txpool + peer, _ := newTestPeer(t, "peer", 2, pm, true) + defer peer.close() + signer := types.HomesteadSigner{} + + wrongAddress := common.HexToAddress("1762042962b8759e17d2b5ac6c5565273df506fd") + cases := []struct { + desc string + tx *types.Transaction + status txStatus + }{{ + desc: "no recipient or fee value attached", + tx: types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, nil, nil, nil), + status: txStatus{Status: core.TxStatusUnknown, Error: "gateway fee recipient must be 0x2aD937cB878D8bEEfC84F3d0545750c2ff78CD0e, got "}, + }, { + desc: "wrong recipient", + tx: types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, &wrongAddress, nil, nil), + status: txStatus{Status: core.TxStatusUnknown, Error: "gateway fee recipient must be 0x2aD937cB878D8bEEfC84F3d0545750c2ff78CD0e, got 0x1762042962b8759E17d2B5Ac6c5565273df506fD"}, + }, { + desc: "no fee value attached", + tx: types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, &pm.etherbase, nil, nil), + status: txStatus{Status: core.TxStatusUnknown, Error: "gateway fee value must be at least 25000, got 0"}, + }, { + desc: "fee value too value", + tx: types.NewTransaction(3, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, &pm.etherbase, new(big.Int).Sub(pm.gatewayFee, big.NewInt(1)), nil), + status: txStatus{Status: core.TxStatusUnknown, Error: "gateway fee value must be at least 25000, got 24999"}, + }, { + desc: "fee value exactly enough", + tx: types.NewTransaction(4, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, &pm.etherbase, pm.gatewayFee, nil), + status: txStatus{Status: core.TxStatusQueued}, + }, { + desc: "fee value more than enough", + tx: types.NewTransaction(5, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil, &pm.etherbase, new(big.Int).Add(pm.gatewayFee, big.NewInt(1)), nil), + status: txStatus{Status: core.TxStatusQueued}, + }} + + for i, c := range cases { + t.Run(c.desc, func(t *testing.T) { + tx, _ := types.SignTx(c.tx, signer, testBankKey) + cost := peer.GetRequestCost(SendTxV2Msg, 1) + if err := sendRequest(peer.app, SendTxV2Msg, uint64(i+1), cost, types.Transactions{tx}); err != nil { + t.Fatalf("transaction send failed: %v", err) + } + if err := expectResponse(peer.app, TxStatusMsg, uint64(i+1), testBufLimit, []txStatus{c.status}); err != nil { + t.Fatalf("transaction status mismatch: %v", err) + } + }) + } +} diff --git a/les/helper_test.go b/les/helper_test.go index c7b849b114..fd925a2523 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -85,7 +85,7 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. @@ -94,11 +94,11 @@ func testChainGen(i int, block *core.BlockGen) { // acc1Addr creates a test event. nonce := block.TxNonce(acc1Addr) - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) - tx3, _ := types.SignTx(types.NewContractCreation(nonce+1, big.NewInt(0), 200000, big.NewInt(0), nil, nil, testContractCode), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce+1, big.NewInt(0), 200000, big.NewInt(0), nil, nil, nil, testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce+1) - tx4, _ := types.SignTx(types.NewContractCreation(nonce+2, big.NewInt(0), 200000, big.NewInt(0), nil, nil, testEventEmitterCode), signer, acc1Key) + tx4, _ := types.SignTx(types.NewContractCreation(nonce+2, big.NewInt(0), 200000, big.NewInt(0), nil, nil, nil, testEventEmitterCode), signer, acc1Key) testEventEmitterAddr = crypto.CreateAddress(acc1Addr, nonce+2) block.AddTx(tx1) block.AddTx(tx2) @@ -109,7 +109,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -120,7 +120,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, nil, data), signer, testBankKey) block.AddTx(tx) } } @@ -178,7 +178,7 @@ func newTestProtocolManager(syncmode downloader.SyncMode, blocks int, generator if lightSync { indexConfig = light.TestClientIndexerConfig } - pm, err := NewProtocolManager(gspec.Config, indexConfig, syncmode, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), common.Address{}) + pm, err := NewProtocolManager(gspec.Config, indexConfig, syncmode, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup), common.Address{}, nil) if err != nil { return nil, err } diff --git a/les/odr_test.go b/les/odr_test.go index 9a8936a01e..d907ddd6b5 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -133,7 +133,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(testBankAddress) from.SetBalance(math.MaxBig256) - msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, false)} + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, bc, nil) vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) @@ -147,7 +147,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(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, data, false)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), nil, nil, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, lc, nil) vmenv := vm.NewEVM(context, state, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) diff --git a/les/server.go b/les/server.go index b435c28a37..fa2adc7c7f 100644 --- a/les/server.go +++ b/les/server.go @@ -52,7 +52,12 @@ type LesServer struct { func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { quitSync := make(chan struct{}) - pm, err := NewProtocolManager(eth.BlockChain().Config(), light.DefaultServerIndexerConfig, downloader.FullSync, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup), config.Etherbase) + pm, err := NewProtocolManager(eth.BlockChain().Config(), + light.DefaultServerIndexerConfig, downloader.FullSync, config.NetworkId, + eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), + eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup), + config.Etherbase, config.GatewayFee, + ) if err != nil { return nil, err } diff --git a/les/txrelay.go b/les/txrelay.go index aaf4d5b8c6..1d1c798139 100644 --- a/les/txrelay.go +++ b/les/txrelay.go @@ -78,12 +78,12 @@ func (self *LesTxRelay) send(txs types.Transactions) { hash := tx.Hash() ltr, ok := self.txSent[hash] if !ok { - p, err := self.ps.getPeerWithEtherbase(*tx.GasFeeRecipient()) + p, err := self.ps.getPeerWithEtherbase(*tx.GatewayFeeRecipient()) // TODO(asa): When this happens, the nonce is still incremented, preventing future txs from being added. // We rely on transactions to be rejected in light/txpool validateTx to prevent transactions - // with GasFeeRecipient != one of our peers from making it to the relayer. + // with GatewayFeeRecipient != one of our peers from making it to the relayer. if err != nil { - log.Error("Unable to find peer with matching etherbase", "err", err, "tx.hash", tx.Hash(), "tx.gasFeeRecipient", tx.GasFeeRecipient()) + log.Error("Unable to find peer with matching etherbase", "err", err, "tx.hash", tx.Hash(), "tx.gatewayFeeRecipient", tx.GatewayFeeRecipient()) continue } sendTo[p] = append(sendTo[p], tx) diff --git a/light/odr_test.go b/light/odr_test.go index bc1e6ed2e3..c5df4eed7f 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -194,7 +194,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), nil, nil, data, false)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), nil, nil, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, chain, nil) vmenv := vm.NewEVM(context, st, config, vm.Config{}) gp := new(core.GasPool).AddGas(math.MaxUint64) @@ -212,17 +212,17 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), signer, acc1Key) nonce++ - tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), nil, nil, testContractCode), signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), nil, nil, nil, testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -232,7 +232,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -243,7 +243,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, nil, nil, nil, data), signer, testBankKey) block.AddTx(tx) } } diff --git a/light/txpool.go b/light/txpool.go index e8778d99de..c60bfd779f 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -18,6 +18,7 @@ package light import ( "context" + "errors" "fmt" "sync" "time" @@ -27,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -43,6 +45,8 @@ const ( // considered permanent and no rollback is expected var txPermanent = uint64(500) +var errGatewayFeeTooLow = errors.New("gateway fee too low to broadcast to peers") + // TxPool implements the transaction pool for light clients, which keeps track // of the status of locally created transactions, detecting if they are included // in a block (mined) or rolled back. There are no queued transactions since we @@ -339,7 +343,7 @@ func (pool *TxPool) Stats() (pending int) { return } -// validateTx checks whether a transaction is valid according to the consensus rules. +// validateTx checks whether a transaction is valid according to the consensus rules and will be broadcast. func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error { // Validate sender var ( @@ -373,14 +377,13 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Transactor should have enough funds to cover the costs - // cost == V + GP * GL err = core.ValidateTransactorBalanceCoversTx(tx, from, currentState) if err != nil { return err } // Should supply enough intrinsic gas - gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, header, currentState, tx.GasCurrency()) + gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead, header, currentState, tx.FeeCurrency()) if err != nil { return err } @@ -389,15 +392,21 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should have a peer that will accept and broadcast our transaction - if tx.GasFeeRecipient() == nil { + if tx.GatewayFeeRecipient() == nil { err = pool.relay.HasPeerWithEtherbase(common.Address{}) } else { - err = pool.relay.HasPeerWithEtherbase(*tx.GasFeeRecipient()) + err = pool.relay.HasPeerWithEtherbase(*tx.GatewayFeeRecipient()) } if err != nil { return err } + // TODO(nategraf): Support fetching the gateway fee from our peers. + // For now we assume our peer is using the default. + if tx.GatewayFeeRecipient() != nil && tx.GatewayFee().Cmp(eth.DefaultConfig.GatewayFee) < 0 { + return errGatewayFeeTooLow + } + return currentState.Error() } diff --git a/light/txpool_test.go b/light/txpool_test.go index 6a6d18416a..3678c43820 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -81,7 +81,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { func TestTxPool(t *testing.T) { for i := range testTx { - testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) } var ( diff --git a/miner/worker.go b/miner/worker.go index 9bc420a8fe..09050bfa90 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -320,7 +320,7 @@ func (w *worker) close() { } func (w *worker) txCmp(tx1 *types.Transaction, tx2 *types.Transaction) int { - return currency.Cmp(tx1.GasPrice(), tx1.GasCurrency(), tx2.GasPrice(), tx2.GasCurrency()) + return currency.Cmp(tx1.GasPrice(), tx1.FeeCurrency(), tx2.GasPrice(), tx2.FeeCurrency()) } // newWorkLoop is a standalone goroutine to submit new mining work upon received events. @@ -792,11 +792,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin if tx == nil { break } - // Check for valid gas currency and that the tx exceeds the gasPriceMinimum + // Check for valid fee currency and that the tx exceeds the gasPriceMinimum // We will not add any more txns from the `txns` parameter if `tx`'s gasPrice is below the gas price minimum. // All the other transactions after this `tx` will either also be below the gas price minimum or will have a // nonce that is non sequential to the last mined txn for the account. - gasPriceMinimum, _ := gpm.GetGasPriceMinimum(tx.GasCurrency(), w.current.header, w.current.state) + gasPriceMinimum, _ := gpm.GetGasPriceMinimum(tx.FeeCurrency(), w.current.header, w.current.state) if tx.GasPrice().Cmp(gasPriceMinimum) == -1 { log.Info("Excluding transaction from block due to failure to exceed gasPriceMinimum", "gasPrice", tx.GasPrice(), "gasPriceMinimum", gasPriceMinimum) break diff --git a/miner/worker_test.go b/miner/worker_test.go index ef9e7aa534..e754d08586 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -77,9 +77,9 @@ func init() { ProposerPolicy: 0, } - tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(0, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) pendingTxs = append(pendingTxs, tx1) - tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(1, testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil, nil, nil), types.HomesteadSigner{}, testBankKey) newTxs = append(newTxs, tx2) } diff --git a/mobile/types.go b/mobile/types.go index d91e803b3d..9597fc24ba 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -198,10 +198,10 @@ type Transaction struct { } // NewTransaction creates a new transaction with the given properties. -func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, gasCurrency, gasFeeRecipient *Address, data []byte) *Transaction { - convertedGasCurrency := common.BytesToAddress(gasCurrency.GetBytes()) - convertedGasFeeRecipient := common.BytesToAddress(gasFeeRecipient.GetBytes()) - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, &convertedGasCurrency, &convertedGasFeeRecipient, common.CopyBytes(data))} +func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, feeCurrency, gatewayFeeRecipient *Address, gatewayFee *BigInt, data []byte) *Transaction { + convertedFeeCurrency := common.BytesToAddress(feeCurrency.GetBytes()) + convertedGatewayFeeRecipient := common.BytesToAddress(gatewayFeeRecipient.GetBytes()) + return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, &convertedFeeCurrency, &convertedGatewayFeeRecipient, gatewayFee.bigint, common.CopyBytes(data))} } // NewTransactionFromRLP parses a transaction from an RLP data dump. diff --git a/params/protocol_params.go b/params/protocol_params.go index a0ff0da9e7..43b4c06b2f 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -113,7 +113,7 @@ var ( BlockchainParametersRegistryId = makeRegistryId("BlockchainParameters") ElectionRegistryId = makeRegistryId("Election") EpochRewardsRegistryId = makeRegistryId("EpochRewards") - GasCurrencyWhitelistRegistryId = makeRegistryId("GasCurrencyWhitelist") + FeeCurrencyWhitelistRegistryId = makeRegistryId("FeeCurrencyWhitelist") GasPriceMinimumRegistryId = makeRegistryId("GasPriceMinimum") GoldTokenRegistryId = makeRegistryId("GoldToken") GovernanceRegistryId = makeRegistryId("Governance") @@ -142,7 +142,8 @@ func makeRegistryId(contractName string) [32]byte { const ( // Default intrinsic gas cost of transactions paying for gas in alternative currencies. - IntrinsicGasForAlternativeGasCurrency uint64 = 134000 + // Calculated to estimate 1 balance read, 1 debit, and 4 credit transactions. + IntrinsicGasForAlternativeFeeCurrency uint64 = 166000 // Contract communication gas limits MaxGasForCalculateTargetEpochPaymentAndRewards uint64 = 2000000 diff --git a/signer/core/types.go b/signer/core/types.go index f043490f05..3c4905ccdf 100644 --- a/signer/core/types.go +++ b/signer/core/types.go @@ -92,14 +92,15 @@ func (v *ValidationMessages) getWarnings() error { // SendTxArgs represents the arguments to submit a transaction type SendTxArgs struct { - From common.MixedcaseAddress `json:"from"` - To *common.MixedcaseAddress `json:"to"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice hexutil.Big `json:"gasPrice"` - GasCurrency *common.MixedcaseAddress `json:"gasCurrency"` - GasFeeRecipient *common.MixedcaseAddress `json:"gasFeeRecipient"` - Value hexutil.Big `json:"value"` - Nonce hexutil.Uint64 `json:"nonce"` + From common.MixedcaseAddress `json:"from"` + To *common.MixedcaseAddress `json:"to"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice hexutil.Big `json:"gasPrice"` + FeeCurrency *common.MixedcaseAddress `json:"feeCurrency"` + GatewayFeeRecipient *common.MixedcaseAddress `json:"gatewayFeeRecipient"` + GatewayFee hexutil.Big `json:"gatewayFee"` + Value hexutil.Big `json:"value"` + Nonce hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. Data *hexutil.Bytes `json:"data"` Input *hexutil.Bytes `json:"input"` @@ -120,18 +121,18 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { } else if args.Input != nil { input = *args.Input } - var gasCurrency *common.Address = nil - if args.GasCurrency != nil { - tmp := args.GasCurrency.Address() - gasCurrency = &tmp + var feeCurrency *common.Address = nil + if args.FeeCurrency != nil { + tmp := args.FeeCurrency.Address() + feeCurrency = &tmp } - var gasFeeRecipient *common.Address = nil - if args.GasFeeRecipient != nil { - tmp := args.GasFeeRecipient.Address() - gasFeeRecipient = &tmp + var gatewayFeeRecipient *common.Address = nil + if args.GatewayFeeRecipient != nil { + tmp := args.GatewayFeeRecipient.Address() + gatewayFeeRecipient = &tmp } if args.To == nil { - return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), uint64(args.Gas), (*big.Int)(&args.GasPrice), gasCurrency, gasFeeRecipient, input) + return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), uint64(args.Gas), (*big.Int)(&args.GasPrice), feeCurrency, gatewayFeeRecipient, (*big.Int)(&args.GatewayFee), input) } - return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), gasCurrency, gasFeeRecipient, input) + return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (uint64)(args.Gas), (*big.Int)(&args.GasPrice), feeCurrency, gatewayFeeRecipient, (*big.Int)(&args.GatewayFee), input) } diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go index 67dedc8604..3e38a145dc 100644 --- a/signer/rules/rules_test.go +++ b/signer/rules/rules_test.go @@ -482,7 +482,7 @@ func dummySigned(value *big.Int) *types.Transaction { gas := uint64(21000) gasPrice := big.NewInt(2000000) data := make([]byte, 0) - return types.NewTransaction(3, to, value, gas, gasPrice, nil, nil, data) + return types.NewTransaction(3, to, value, gas, gasPrice, nil, nil, nil, data) } func TestLimitWindow(t *testing.T) { diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 7dec19e548..5fbaaf0d27 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -243,7 +243,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { return nil, fmt.Errorf("invalid tx data %q", dataHex) } - msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, nil, nil, data, true) + msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, nil, nil, common.Big0, data, true) return msg, nil }