Skip to content

Commit

Permalink
EIP1559 (#4155)
Browse files Browse the repository at this point in the history
* npm run build for 1.4.0-rc.0

* v1.4.0-rc.0

* Update scripts/e2e.geth.instamine.sh to use v1.10.3 of Geth

* Update scripts/e2e.geth.instamine.sh to use v1.10.3 of Geth

* Fix typo

* WIP

* Fix type in error catch

Co-authored-by: Gregory Markou <16929357+GregTheGreek@users.noreply.github.com>

* Remove commented code

* Update index for tx pricing info

* Correct order of if statements to properly assign tx type

* Update maxFeePerGas calculation

* Init _handleTxType function

* Update _handleTxPricing to use gasPrice for eip-1559 txs

* Fix bugs in _handleTxPricing

* Update tests for eip-1559 changes

* Fix BN bug: .mul only accepts BN instances

* eth.accounts.signTransaction: Add London tests

* Add EIP-1559 test without AccessList

* Add tx.common.hardfork check to _handleTxType

* Bug fixes

* Add additional undefined check in _handleTxType

* Add additional check for tx.hardfork in _handleTxType

* Add additional check for tx.hardfork in _handleTxType

* Update CHANGELOG

* Handling EIP1559 transactions in outputTransactionFormatter (#4167)

* Handing a null gasPrice and supporting maxFeePerGas and maxPriorityFeePerGas

* Updating gasPrice check

* Revert geth docker version tag

* Add additional EIP-2930 and EIP-1559 tests

* EIP 1559 Debug #2 (#4171)

* Add additional EIP-2930 and EIP-1559 tests

* Update gasPrice to geth default minimum

* Replace hex number with number string

* Add test skip if using Ganache

* Add done function to ganache skip

* Add done function to ganache skip

* Update gasPrice params

* Bump gasPrice to Geth default

* Bump docker geth version to stable

* Gas price type number for 1 Gwei

* gasPrice type and backfills timeout change

* gasPrice type and test acct creation

* added nonce for geth auto nonce issue, removed auto acct creation

* Remove redundant London test. Add gasLimit field to London test

* Add validation for tx.maxPriorityFeePerGas and tx.maxFeePerGas

* Add additional 1559 tests

Co-authored-by: jdevcs <junaid@chainsafe.com>
Co-authored-by: jdevcs <junaid@chainsafe.io>

* Update error message

Co-authored-by: Gregory Markou <16929357+GregTheGreek@users.noreply.github.com>

* Update error message

Co-authored-by: Gregory Markou <16929357+GregTheGreek@users.noreply.github.com>

* Update use of tx.type

* Replace hardfork strings with enum

* Type check refactors for _handleTxPricing

* Resolve tx.gasPrice if set and tx.type < 0x2 in _handleTxPricing

* Fix _handleTxType logic

Co-authored-by: Gregory Markou <16929357+GregTheGreek@users.noreply.github.com>
Co-authored-by: Cory Smith <cory.m.smith@gmail.com>
Co-authored-by: jdevcs <junaid@chainsafe.com>
Co-authored-by: jdevcs <junaid@chainsafe.io>
  • Loading branch information
5 people authored Jul 21, 2021
1 parent 9b7540d commit 6ba267b
Show file tree
Hide file tree
Showing 16 changed files with 6,239 additions and 9,346 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,10 @@ Released with 1.0.0-beta.37 code base.

- Removing the underscore package

## [Unreleased]
## [Unreleased]

## [1.5.0]

### Added

- London transaction support (#4155)
14,889 changes: 5,598 additions & 9,291 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion packages/web3-core-helpers/src/formatters.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,14 @@ var outputTransactionFormatter = function (tx) {
tx.transactionIndex = utils.hexToNumber(tx.transactionIndex);
tx.nonce = utils.hexToNumber(tx.nonce);
tx.gas = utils.hexToNumber(tx.gas);
tx.gasPrice = outputBigNumberFormatter(tx.gasPrice);
if (tx.gasPrice)
tx.gasPrice = outputBigNumberFormatter(tx.gasPrice);
if (tx.maxFeePerGas)
tx.maxFeePerGas = outputBigNumberFormatter(tx.maxFeePerGas);
if (tx.maxPriorityFeePerGas)
tx.maxPriorityFeePerGas = outputBigNumberFormatter(tx.maxPriorityFeePerGas);
if (tx.type)
tx.type = utils.hexToNumber(tx.type);
tx.value = outputBigNumberFormatter(tx.value);

if (tx.to && utils.isAddress(tx.to)) { // tx.to could be `0x0` or `null` while contract creation
Expand Down
163 changes: 144 additions & 19 deletions packages/web3-eth-accounts/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var utils = require('web3-utils');
var helpers = require('web3-core-helpers');
var {TransactionFactory} = require('@ethereumjs/tx');
var Common = require('@ethereumjs/common').default;

var HardForks = require('@ethereumjs/common').Hardfork;

var isNot = function(value) {
return (typeof value === 'undefined') || value === null;
Expand Down Expand Up @@ -80,7 +80,17 @@ var Accounts = function Accounts() {
}, function() {
return 'latest';
}]
})
}),
new Method({
name: 'getBlockByNumber',
call: 'eth_getBlockByNumber',
params: 2,
inputFormatter: [function(blockNumber) {
return blockNumber ? utils.toHex(blockNumber) : 'latest'
}, function() {
return false
}]
}),
];
// attach methods to this._ethereumCall
this._ethereumCall = {};
Expand Down Expand Up @@ -157,11 +167,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
transaction.data = transaction.data || '0x';
transaction.value = transaction.value || '0x';
transaction.gasLimit = transaction.gasLimit || transaction.gas;
transaction.type = "0x0"; // default to legacy
if (transaction.accessList) {
// EIP-2930
transaction.type = "0x01"
}
if (transaction.type === '0x1' && transaction.accessList === undefined) transaction.accessList = []

// Because tx has no @ethereumjs/tx signing options we use fetched vals.
if (!hasTxSigningOptions) {
Expand All @@ -172,7 +178,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
networkId: transaction.networkId,
chainId: transaction.chainId
},
transaction.hardfork || "berlin"
transaction.hardfork || HardForks.London
);

delete transaction.networkId;
Expand All @@ -185,7 +191,7 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
networkId: transaction.common.customChain.networkId,
chainId: transaction.common.customChain.chainId
},
transaction.common.hardfork || "berlin",
transaction.common.hardfork || HardForks.London,
);

delete transaction.common;
Expand Down Expand Up @@ -238,23 +244,42 @@ Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, ca
}
}

tx.type = _handleTxType(tx);

// Resolve immediately if nonce, chainId, price and signing options are provided
if (tx.nonce !== undefined && tx.chainId !== undefined && tx.gasPrice !== undefined && hasTxSigningOptions) {
if (
tx.nonce !== undefined &&
tx.chainId !== undefined &&
(
tx.gasPrice !== undefined ||
(
tx.maxFeePerGas !== undefined &&
tx.maxPriorityFeePerGas !== undefined
)
) &&
hasTxSigningOptions
) {
return Promise.resolve(signed(tx));
}

// Otherwise, get the missing info from the Ethereum Node
return Promise.all([
isNot(tx.chainId) ? _this._ethereumCall.getChainId() : tx.chainId,
isNot(tx.gasPrice) ? _this._ethereumCall.getGasPrice() : tx.gasPrice,
isNot(tx.nonce) ? _this._ethereumCall.getTransactionCount(_this.privateKeyToAccount(privateKey).address) : tx.nonce,
isNot(hasTxSigningOptions) ? _this._ethereumCall.getNetworkId() : 1
isNot(hasTxSigningOptions) ? _this._ethereumCall.getNetworkId() : 1,
_handleTxPricing(_this, tx)
]).then(function(args) {
if (isNot(args[0]) || isNot(args[1]) || isNot(args[2]) || isNot(args[3])) {
throw new Error('One of the values "chainId", "networkId", "gasPrice", or "nonce" couldn\'t be fetched: ' + JSON.stringify(args));
}
return signed({ ...tx, chainId: args[0], gasPrice: args[1], nonce: args[2], networkId: args[3]});

return signed({
...tx,
chainId: args[0],
nonce: args[1],
networkId: args[2],
...args[3] // Will either be gasPrice or maxFeePerGas and maxPriorityFeePerGas
});
});
};

Expand All @@ -272,20 +297,120 @@ function _validateTransactionForSigning(tx) {
);
}

if (!tx.gas && !tx.gasLimit) {
if (
(!tx.gas && !tx.gasLimit) &&
(!tx.maxPriorityFeePerGas && !tx.maxFeePerGas)
) {
return new Error('"gas" is missing');
}

if (tx.nonce < 0 ||
tx.gas < 0 ||
tx.gasPrice < 0 ||
tx.chainId < 0) {
return new Error('Gas, gasPrice, nonce or chainId is lower than 0');
if (tx.gas && tx.gasPrice) {
if (tx.gas < 0 || tx.gasPrice < 0) {
return new Error('Gas or gasPrice is lower than 0');
}
} else {
if (tx.maxPriorityFeePerGas < 0 || tx.maxFeePerGas < 0) {
return new Error('maxPriorityFeePerGas or maxFeePerGas is lower than 0');
}
}

if (tx.nonce < 0 || tx.chainId < 0) {
return new Error('Nonce or chainId is lower than 0');
}

return;
}

function _handleTxType(tx) {
// Taken from https://github.com/ethers-io/ethers.js/blob/2a7ce0e72a1e0c9469e10392b0329e75e341cf18/packages/abstract-signer/src.ts/index.ts#L215
const hasEip1559 = (tx.maxFeePerGas !== undefined || tx.maxPriorityFeePerGas !== undefined);

let txType;

if (tx.type !== undefined) {
txType = utils.toHex(tx.type)
} else if (tx.type === undefined && hasEip1559) {
txType = '0x2'
} else {
txType = '0x0'
}

if (tx.gasPrice !== undefined && (txType === '0x2' || hasEip1559))
throw Error("eip-1559 transactions don't support gasPrice");
if ((txType === '0x1' || txType === '0x0') && hasEip1559)
throw Error("pre-eip-1559 transaction don't support maxFeePerGas/maxPriorityFeePerGas");

if (
hasEip1559 ||
(
(tx.common && tx.common.hardfork && tx.common.hardfork.toLowerCase() === HardForks.London) ||
(tx.hardfork && tx.hardfork.toLowerCase() === HardForks.London)
)
) {
txType = '0x2';
} else if (
tx.accessList ||
(
(tx.common && tx.common.hardfork && tx.common.hardfork.toLowerCase() === HardForks.Berlin) ||
(tx.hardfork && tx.hardfork.toLowerCase() === HardForks.Berlin)
)
) {
txType = '0x1';
}

return txType
}

function _handleTxPricing(_this, tx) {
return new Promise((resolve, reject) => {
try {
if (tx.type < '0x2' && tx.gasPrice !== undefined) {
// Legacy transaction, return provided gasPrice
resolve({ gasPrice: tx.gasPrice })
} else {
Promise.all([
_this._ethereumCall.getBlockByNumber(),
_this._ethereumCall.getGasPrice()
]).then(responses => {
const [block, gasPrice] = responses;
if (
(tx.type === '0x2') &&
block && block.baseFeePerGas
) {
// The network supports EIP-1559

// Taken from https://github.com/ethers-io/ethers.js/blob/ba6854bdd5a912fe873d5da494cb5c62c190adde/packages/abstract-provider/src.ts/index.ts#L230
let maxPriorityFeePerGas, maxFeePerGas;

if (tx.gasPrice) {
// Using legacy gasPrice property on an eip-1559 network,
// so use gasPrice as both fee properties
maxPriorityFeePerGas = tx.gasPrice;
maxFeePerGas = tx.gasPrice;
delete tx.gasPrice;
} else {
maxPriorityFeePerGas = tx.maxPriorityFeePerGas || '0x3B9ACA00'; // 1 Gwei
maxFeePerGas = tx.maxFeePerGas ||
utils.toHex(
utils.toBN(block.baseFeePerGas)
.mul(utils.toBN(2))
.add(utils.toBN(maxPriorityFeePerGas))
);
}
resolve({ maxFeePerGas, maxPriorityFeePerGas });
} else {
if (tx.maxPriorityFeePerGas || tx.maxFeePerGas)
throw Error("Network doesn't support eip-1559")
resolve({ gasPrice });
}
})
}
} catch (error) {
reject(error)
}
})
}

/* jshint ignore:start */
Accounts.prototype.recoverTransaction = function recoverTransaction(rawTx, txOptions = {}) {
// Rely on EthereumJs/tx to determine the type of transaction
Expand Down
2 changes: 1 addition & 1 deletion scripts/e2e.geth.automine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ echo " "
# Launch client w/ two unlocked accounts.
# + accounts[0] default geth unlocked bal = ~infinity
# + accounts[1] unlocked, signing password = 'left-hand-of-darkness'
geth-dev-assistant --period 2 --accounts 1 --tag 'v1.10.3'
geth-dev-assistant --period 2 --accounts 1 --tag 'stable'

# Test
GETH_AUTOMINE=true nyc --no-clean --silent _mocha -- \
Expand Down
2 changes: 1 addition & 1 deletion scripts/e2e.geth.instamine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ echo " "
# Launch client w/ two unlocked accounts.
# + accounts[0] default geth unlocked bal = ~infinity
# + accounts[1] unlocked, bal=50 eth, signing password = 'left-hand-of-darkness'
geth-dev-assistant --accounts 1 --tag 'v1.10.3'
geth-dev-assistant --accounts 1 --tag 'stable'

# Test
GETH_INSTAMINE=true nyc --no-clean --silent _mocha -- \
Expand Down
2 changes: 1 addition & 1 deletion scripts/js/ens.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async function setupENS(web3) {

const options = {
bytecode: undefined,
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 5500000
}

Expand Down
6 changes: 3 additions & 3 deletions test/e2e.contract.deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ describe('contract.deploy [ @E2E ]', function() {

var basicOptions = {
data: Basic.bytecode,
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 4000000
};

var revertsOptions = {
data: Reverts.bytecode,
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 4000000
}

var noBytecodeOptions = {
data: '0x',
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 4000000
}

Expand Down
6 changes: 3 additions & 3 deletions test/e2e.contract.events.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('contract.events [ @E2E ]', function() {

var basicOptions = {
data: Basic.bytecode,
gasPrice: '1',
gasPrice: 1000000000,// Default gasPrice set by Geth
gas: 4000000
};

Expand Down Expand Up @@ -289,7 +289,7 @@ describe('contract.events [ @E2E ]', function() {
let contract;

const options = {
gasPrice: '1',
gasPrice: 1000000000,// Default gasPrice set by Geth
gas: 4000000
};

Expand Down Expand Up @@ -336,7 +336,7 @@ describe('contract.events [ @E2E ]', function() {
// and geth instamine's websockets connection is too fragile for the tests in this file.
it('backfills missed events when auto-reconnecting', function(){
if(!process.env.GANACHE) return;
this.timeout(10000);
this.timeout(20000);

let counter = 0;
const acc = accounts[0];
Expand Down
2 changes: 1 addition & 1 deletion test/e2e.ens.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('ENS [ @E2E ]', function () {
options = {
from: account,
gas: 4000000,
gasPrice: 1
gasPrice: 1000000000 // Default gasPrice set by Geth
}
});

Expand Down
4 changes: 2 additions & 2 deletions test/e2e.method.call.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ describe('method.call [ @E2E ]', function () {

var basicOptions = {
data: Basic.bytecode,
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 4000000
};

var miscOptions = {
data: Misc.bytecode,
gasPrice: '1',
gasPrice: 1000000000, // Default gasPrice set by Geth
gas: 4000000
};

Expand Down
Loading

0 comments on commit 6ba267b

Please sign in to comment.