Skip to content

Commit

Permalink
eth_createAccessList - Closes #4081 (#4332)
Browse files Browse the repository at this point in the history
* Init web3.eth.createAccessList

* Init e2e test for createAccessList

* Add createAccessList method to method wrappers for contracts

* Update failing tests to use dynamic address

* Add check to not run tests if ENV not Geth

* Add createAccessList to docs

* Update CHANGELOG.md

* Update docs/web3-eth-contract.rst

* Update docs/web3-eth-contract.rst

* Update docs/web3-eth-contract.rst

* Update docs/web3-eth-contract.rst

* Update docs/web3-eth-contract.rst

* Update docs/web3-eth.rst

* Remove duplicate line in CHANGELOG

* Move CHANGELOG addition to 1.6.1
  • Loading branch information
spacesailor24 committed Oct 5, 2021
1 parent dbb4350 commit 3a3cb32
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,10 @@ Released with 1.0.0-beta.37 code base.

## [1.6.1]

### Added

- Support for `eth_createAccessList` as both an rpc call (`web3.eth.createAccessList`) and property of contract method wrappers (`contractInstance.methods.getValue().createAccessList`) (#4332)

### Changed

- Not considering `tx.chainId` if `tx.common.customChain.chainId` is provided for `web3.eth.accounts.signTransaction` function (#4293)
Expand All @@ -466,3 +470,4 @@ Released with 1.0.0-beta.37 code base.
- Emit subscription id with connect event when creating a subscription (#4300)
- Introduced new configuration "blockHeaderTimeout" for waiting of block headers for transaction receipt (#3891)
- Format `block.baseFeePerGas` to number (#4330)
- Updated README to include Webpack 5 angular support instructions (#4174)
71 changes: 70 additions & 1 deletion docs/web3-eth-contract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ Returns
- ``Function`` - :ref:`send <contract-send>`: Will deploy the contract. The promise will resolve with the new contract instance, instead of the receipt!
- ``Function`` - :ref:`estimateGas <contract-estimateGas>`: Will estimate the gas used for deploying. Note: You must specify a ``from`` address otherwise you may experience odd behavior.
- ``Function`` - :ref:`encodeABI <contract-encodeABI>`: Encodes the ABI of the deployment, which is contract data + constructor parameters
- ``Function`` - :ref:`createAccessList <contract-createAccessList>`: Returns an EIP-2930 access list for specified contract method Note: You must specify a ``from`` address and possible ``gas``

-------
Example
Expand Down Expand Up @@ -684,7 +685,7 @@ methods
myContract.methods.myMethod([param1[, param2[, ...]]])
Creates a transaction object for that method, which then can be :ref:`called <contract-call>`, :ref:`send <contract-send>`, :ref:`estimated <contract-estimateGas>`, or :ref:`ABI encoded <contract-encodeABI>`.
Creates a transaction object for that method, which then can be :ref:`called <contract-call>`, :ref:`send <contract-send>`, :ref:`estimated <contract-estimateGas>`, :ref:`createAccessList <contract-createAccessList>` , or :ref:`ABI encoded <contract-encodeABI>`.

The methods of this smart contract are available through:

Expand All @@ -711,6 +712,7 @@ Returns
- ``Function`` - :ref:`send <contract-send>`: Will send a transaction to the smart contract and execute its method (Can alter the smart contract state).
- ``Function`` - :ref:`estimateGas <contract-estimateGas>`: Will estimate the gas used when the method would be executed on chain. Note: You must specify a ``from`` address otherwise you may experience odd behavior.
- ``Function`` - :ref:`encodeABI <contract-encodeABI>`: Encodes the ABI for this method. This can be send using a transaction, call the method or passing into another smart contracts method as argument.
- ``Function`` - :ref:`createAccessList <contract-createAccessList>`: Returns an EIP-2930 access list for specified contract method Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``).

-------
Example
Expand Down Expand Up @@ -1038,6 +1040,73 @@ Example
> '0x58cf5f1000000000000000000000000000000000000000000000000000000000000007B'
------------------------------------------------------------------------------

.. _contract-createAccessList:

methods.myMethod.createAccessList
=====================

.. code-block:: javascript
myContract.methods.myMethod([param1[, param2[, ...]]]).createAccessList(options, blockHashOrBlockNumber [, callback])
Will call to create an access list a method execution will access when executed in the EVM.
Note: Currently `eth_createAccessList` seems to only be supported by Geth.
Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``).

----------
Parameters
----------

1. ``options`` - ``Object``: The options used for calling.
* ``from`` - ``String``: The address the call "transaction" should be made from.
* ``gas`` - ``Number`` (optional): The maximum gas provided for this call "transaction" (gas limit). Setting a specific value helps to detect out of gas errors. Access list response will return amount of gas used.
2. ``block`` - ``String|Number|BN|BigNumber`` (optional): The block number or hash. Or the string ``"earliest"``, ``"latest"`` or ``"pending"`` as in the :ref:`default block parameter <eth-defaultblock>`.
3. ``callback`` - ``Function`` (optional): This callback will be fired with the result of the access list generation as the second argument, or with an error object as the first argument.

-------
Returns
-------

``Promise`` returns ``Object``: The generated access list for transaction.

.. code-block:: javascript
{
"accessList": [
{
"address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
],
"gasUsed": "0x644e"
}
-------
Example
-------

.. code-block:: javascript
// using the callback
myContract.methods.myMethod(123).createAccessList({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', gas: 5000000}, function(error, accessList){
...
});
// using the promise
myContract.methods.myMethod(123).createAccessList({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', gas: 5000000})
.then(function(accessList){
...
})
.catch(function(error){
...
});
------------------------------------------------------------------------------


Expand Down
59 changes: 59 additions & 0 deletions docs/web3-eth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2153,3 +2153,62 @@ Example
}
------------------------------------------------------------------------------

createAccessList
=====================

.. code-block:: javascript
web3.eth.createAccessList(callObject [, callback])
Will call to create an access list a method execution will access when executed in the EVM.
Note: Currently `eth_createAccessList` seems to only be supported by Geth.
Note: You must specify a ``from`` address and ``gas`` if it's not specified in ``options`` when instantiating parent contract object (e.g. ``new web3.eth.Contract(jsonInterface[, address][, options])``).

----------
Parameters
----------

1. A transaction object, see :ref:`web3.eth.sendTransaction <eth-sendtransaction-return>` with the difference that this method is specifically for contract method executions.
2. ``block`` - ``String|Number|BN|BigNumber`` (optional): The block number or hash. Or the string ``"earliest"``, ``"latest"`` or ``"pending"`` as in the :ref:`default block parameter <eth-defaultblock>`.
3. ``callback`` - ``Function`` (optional): This callback will be fired with the result of the access list generation as the second argument, or with an error object as the first argument.


-------
Returns
-------

``Promise`` returns ``Object``: The generated access list for transaction.

.. code-block:: javascript
{
"accessList": [
{
"address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
],
"gasUsed": "0x644e"
}
-------
Example
-------


.. code-block:: javascript
web3.eth.createAccessList({
from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312',
data: '0x20965255',
gasPrice: '0x3b9aca00',
gas: '0x3d0900',
to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7'
})
.then(console.log);
------------------------------------------------------------------------------
21 changes: 21 additions & 0 deletions packages/web3-eth-contract/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ Contract.prototype._createTxObject = function _createTxObject(){
txObject.send.request = this.parent._executeMethod.bind(txObject, 'send', true); // to make batch requests
txObject.encodeABI = this.parent._encodeMethodABI.bind(txObject);
txObject.estimateGas = this.parent._executeMethod.bind(txObject, 'estimate');
txObject.createAccessList = this.parent._executeMethod.bind(txObject, 'createAccessList');

if (args && this.method.inputs && args.length !== this.method.inputs.length) {
if (this.nextMethod) {
Expand Down Expand Up @@ -916,6 +917,26 @@ Contract.prototype._executeMethod = function _executeMethod(){
}

switch (args.type) {
case 'createAccessList':

// return error, if no "from" is specified
if(!utils.isAddress(args.options.from)) {
return utils._fireError(errors.ContractNoFromAddressDefinedError(), defer.eventEmitter, defer.reject, args.callback);
}

var createAccessList = (new Method({
name: 'createAccessList',
call: 'eth_createAccessList',
params: 2,
inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter],
requestManager: _this._parent._requestManager,
accounts: ethAccounts, // is eth.accounts (necessary for wallet signing)
defaultAccount: _this._parent.defaultAccount,
defaultBlock: _this._parent.defaultBlock
})).createFunction();

return createAccessList(args.options, args.callback);

case 'estimate':

var estimateGas = (new Method({
Expand Down
6 changes: 6 additions & 0 deletions packages/web3-eth/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,12 @@ var Eth = function Eth() {
params: 0,
outputFormatter: formatter.outputTransactionFormatter
}),
new Method({
name: 'createAccessList',
call: 'eth_createAccessList',
params: 2,
inputFormatter: [formatter.inputTransactionFormatter, formatter.inputDefaultBlockNumberFormatter],
}),

// subscriptions
new Subscriptions({
Expand Down
76 changes: 76 additions & 0 deletions test/e2e.eth.createAccessList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
var assert = require('assert');
var Basic = require('./sources/Basic');
var Misc = require('./sources/Misc');
var utils = require('./helpers/test.utils');
var Web3 = utils.getWeb3();

describe('method.call [ @E2E ]', function () {
var web3;
var accounts;
var basic;
var instance;
var options;

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

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

describe('http', function () {
before(async function () {
web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts();

basic = new web3.eth.Contract(Basic.abi, basicOptions);
instance = await basic.deploy().send({from: accounts[0]});
})

it('returns expected access list for getValue', async function () {
// Currently only Geth supports eth_createAccessList
if (process.env.GANACHE || global.window ) return

var expected = {
accessList: [
{
address: instance.options.address.toLowerCase(),
storageKeys: ["0x0000000000000000000000000000000000000000000000000000000000000000"]
}
],
gasUsed: '0x644e'
};

assert.deepEqual(
await instance.methods.getValue().createAccessList({from: accounts[0]}),
expected
);
});

it('returns expected access list for setValue', async function () {
// Currently only Geth supports eth_createAccessList
if (process.env.GANACHE || global.window ) return

var expected = {
accessList: [
{
address: instance.options.address.toLowerCase(),
storageKeys: ["0x0000000000000000000000000000000000000000000000000000000000000000"]
}
],
gasUsed: '0xb2f5'
}


assert.deepEqual(
await instance.methods.setValue(1).createAccessList({from: accounts[0]}),
expected
);
});
});
});
49 changes: 49 additions & 0 deletions test/eth.createAccessList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
var testMethod = require('./helpers/test.method.js');

var method = 'createAccessList';

var tests = [{
args: [{
from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312',
data: '0x20965255',
gasPrice: '0x3b9aca00',
gas: '0x3d0900',
to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7'
}],
formattedArgs: [
{
from: '0x3bc5885c2941c5cda454bdb4a8c88aa7f248e312',
data: '0x20965255',
gasPrice: '0x3b9aca00',
gas: '0x3d0900',
to: '0x00f5f5f3a25f142fafd0af24a754fafa340f32c7'
},
'latest'
],
result: {
"accessList": [
{
"address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
],
"gasUsed": "0x644e"
},
formattedResult: {
"accessList": [
{
"address": "0x00f5f5f3a25f142fafd0af24a754fafa340f32c7",
"storageKeys": [
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
],
"gasUsed": "0x644e"
},
call: 'eth_'+ method
}];

testMethod.runTests('eth', method, tests);

0 comments on commit 3a3cb32

Please sign in to comment.