Skip to content

Commit

Permalink
eth/tx: update tx initcode cost for shanghai (#237)
Browse files Browse the repository at this point in the history
* eth/tx: update tx initcode cost for shanghai

* ci: patch geth

* ci: patch geth

* ci: patch geth

* spec: update ethereum/test fixtures
  • Loading branch information
q9f committed May 26, 2023
1 parent 041aa92 commit 92e6c54
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 41 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ jobs:
sudo apt-get update
sudo apt-get install ethereum solc libyaml-dev
if: startsWith(matrix.os, 'Ubuntu')
- name: Patch Geth # https://github.com/ethereum/go-ethereum/pull/27360
run: |
git clone https://github.com/q9f/go-ethereum.git -b q9f/params/shanghai
pushd go-ethereum/
make geth
popd
- name: Run Geth
run: |
geth --dev --http --ipcpath /tmp/geth.ipc &
disown &
./go-ethereum/build/bin/geth --dev --http --ipcpath /tmp/geth.ipc &
- name: Gem Dependencies
run: |
git submodule update --init
Expand Down
2 changes: 1 addition & 1 deletion lib/eth/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def transact(contract, function, *args, **kwargs)
gas_limit = if kwargs[:gas_limit]
kwargs[:gas_limit]
else
Tx.estimate_intrinsic_gas(contract.bin) + Tx::CREATE_GAS
Tx.estimate_intrinsic_gas(contract.bin)
end
fun = contract.functions.select { |func| func.name == function }[0]
params = {
Expand Down
11 changes: 9 additions & 2 deletions lib/eth/tx.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class ParameterError < TypeError; end
# The calldata gas cost of a zero byte.
COST_ZERO_BYTE = 4.freeze

# The initcode gas cost for each word (32 bytes).
COST_INITCODE_WORD = 2.freeze

# The access list gas cost of a storage key as per EIP-2930.
COST_STORAGE_KEY = 1_900.freeze

Expand Down Expand Up @@ -156,7 +159,7 @@ def unsigned_copy(tx)
end

# Estimates intrinsic gas for provided call data (EIP-2028) and
# access lists (EIP-2930).
# access lists (EIP-2930). Respects initcode word cost (EIP-3860).
#
# @param data [String] the call data.
# @param list [Array] the access list.
Expand All @@ -173,6 +176,10 @@ def estimate_intrinsic_gas(data = "", list = [])
# count non-zero bytes
none = data.size - zero
gas += none * COST_NON_ZERO_BYTE

# count "words" as per EIP-3860
word_count = (data.length.to_f / 32.0).ceil
gas += word_count * COST_INITCODE_WORD
end
unless list.nil? or list.empty?
list.each do |entry|
Expand All @@ -187,7 +194,7 @@ def estimate_intrinsic_gas(data = "", list = [])
end
end
end
return gas
return gas.to_i
end

# Validates the common transaction fields such as nonce, gas limit,
Expand Down
20 changes: 10 additions & 10 deletions spec/eth/tx/eip2930_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@
sample = Tx.new({
nonce: 0,
gas_price: 0x0BA43B7400,
gas_limit: 0x073a0,
gas_limit: 0x07b50,
to: "0x7917bc33eea648809c285607579c9919fb864f8f",
value: 0x03BAF82D03A000,
access_list: list,
Expand All @@ -257,8 +257,8 @@
expected_address = Address.new "8d900bfa2353548a4631be870f99939575551b60"

# a secp256k1 signature over keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList]))
expected_sign_data = "01f89d0180850ba43b74008273a0947917bc33eea648809c285607579c9919fb864f8f8703baf82d03a00080f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c0"
expected_sign_hash = "c129e3830bdfca2973a26d718b92b5f10564b2f57a02fa0f3888de3273d5b974"
expected_sign_data = "01f89d0180850ba43b7400827b50947917bc33eea648809c285607579c9919fb864f8f8703baf82d03a00080f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c0"
expected_sign_hash = "81f7bf86cf365f50ef2a9663c4f3001c22394ccd891cd1be8ef59af94d2b1b45"

# first byte is type 01 as per EIP-2930
expect(Util.bin_to_hex (sample.unsigned_encoded)[0, 1]).to eq "01"
Expand Down Expand Up @@ -288,15 +288,15 @@
-4153010759215853346544872368790226810347211436084119296615430562753409734914,
]
}
subject(:expected_hex) { "01f90181018001827b448080b8c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000003ea1e26a2119b038eaf9b27e65cdb401502ae7a43d8bfb1368aee2693eb325af9f81244b19304b087b4941a1e892da50bd48dfe1f6d17aad7aff1c87e8481f30395a1595a07b483032affed044e698bf7c43a6fe000000000000000000000000000000000000000000000000000000000000000d4c6f72656d2c20497073756d2100000000000000000000000000000000000000f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c001a047abf8694b14a2d84b5b8e0d8270e79f7772ac71419f5770ce7318bfaae952dba0141d4c6e7cad5af300a1c90924704394a09f9f3476b7c1a219ee799ffb91e765" }
subject(:expected_hash) { "800a8f4816dffee600600cd36f202b14e2d802ae7369aafae9ecb0e5c4906cbc" }
subject(:expected_hex) { "01f90181018001827b508080b8c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000003ea1e26a2119b038eaf9b27e65cdb401502ae7a43d8bfb1368aee2693eb325af9f81244b19304b087b4941a1e892da50bd48dfe1f6d17aad7aff1c87e8481f30395a1595a07b483032affed044e698bf7c43a6fe000000000000000000000000000000000000000000000000000000000000000d4c6f72656d2c20497073756d2100000000000000000000000000000000000000f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c080a001101750fe4fc89a413e65c7e9ef459180742ef68bda055c35761c84302cad13a037dd31afd4c84fb46fec9120934247662399aa053ce7b5b724275239b15ee3ad" }
subject(:expected_hash) { "3559540a9e9a228a240643f2f3b3823e5c8ffa41a5d8f37907ea91d50ef59979" }

it "can create transactions with binary data" do
abi = Abi.encode types, args
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 31_556,
gas_limit: 31_568,
data: abi,
access_list: list,
})
Expand All @@ -322,7 +322,7 @@
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 31_556,
gas_limit: 31_568,
data: hex,
access_list: list,
})
Expand All @@ -349,13 +349,13 @@
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 29_808,
gas_limit: 29_810,
data: lorem,
access_list: list,
})
some.sign cow
expect(some.hex).to eq "01f8cd01800182747080808d4c6f72656d2c20497073756d21f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c080a0aa8fb1b77d26ee25034e7012fd5098c2ffb46ec26f852f492adf38d0ce4480a3a019b93db449c5320f237d6ffa2612055afb8b4286c5f7fe9123c78a287b61af91"
expect(some.hash).to eq "8a3ac899feaf2260701cd92fb094924b0453552286e867f56c4d0c41d1214c25"
expect(some.hex).to eq "01f8cd01800182747280808d4c6f72656d2c20497073756d21f872f85994de0b295669a9fd93d5f28d9ec85e40f4cb697baef842a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000007d694bb9bc244d798123fde783fcc1c72d3bb8c189413c080a017c081b8c851fa7df558054e93539f20b0937aafed06586a2ad59824d52a6f55a00f40033eec8ff5ce9d37270a4170a5d2349142d1f5d0df5064439f60ee6c78be"
expect(some.hash).to eq "52d5c664c2c2da1970f192a2bc8097f22a77035fceef26a9bd00a00473fe035b"

# expect to match both decoded transaction and decoded abi
other = Tx.decode some.hex
Expand Down
44 changes: 22 additions & 22 deletions spec/eth/tx/legacy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@
}
subject(:cow) { Key.new(priv: Util.keccak256("cow")) }

# ref https://goerli.etherscan.io/tx/0x1975df4e715ce4af46c604e3fafb763a51cc133a42e43566779b4d5608bb4af1
# ref https://sepolia.etherscan.io/tx/0x7613b4de482fcff616e11907d16ddba1aa950a020ec58e99ab28ba0c5926ec53
subject(:legacy) {
Tx.new(
{
nonce: 1,
gas_price: 40 * Unit::GWEI,
gas_limit: 21576,
gas_limit: 21580,
to: "0xcaa29806044a08e533963b2e573c1230a2cd9a2d",
value: BigDecimal("0.123456789012345678") * Unit::ETHER,
data: "Lorem Ipsum Ruby Ethereum Test 1-2-3",
},
Chain::GOERLI
Chain::SEPOLIA
)
}

# ref https://goerli.etherscan.io/tx/0x047e319fc8e587a77f6e9a13c30d90b5a741d93e8b35a54b12c91d6149eda359
# ref https://sepolia.etherscan.io/tx/0x01fa6584df6326dc503ca809c9c4643cd753ba8ae63473a9994770f403cda447
subject(:ruby) {
Tx.new(
{
Expand All @@ -38,12 +38,12 @@
value: 0.0069 * Unit::ETHER,
data: "Foo Bar Ruby Ethereum",
},
Chain::GOERLI
Chain::SEPOLIA
)
}

# ref https://goerli.etherscan.io/address/0x4762119a7249823d18aec7eab73258b2d5061dd8
subject(:testnet) { Key.new(priv: "0xc6c633f85d3f9a4705623b1d9bd1122a1a9196cd53dd352505e895fcbb8452ef") }
# ref https://sepolia.etherscan.io/address/0xc3c8fd0f04b629c5e2297b79c54dd57b85a721e3
subject(:testnet) { Key.new(priv: "0xa0d1f18547caa1fb5c121c862d8ac66d9d6afe0afa79b291ca197e64fdccfd23") }

describe ".decode" do
it "decodes the first mainnet transaction" do
Expand Down Expand Up @@ -76,11 +76,11 @@
expect(tx.hash).to eq expected_hash
end

it "decodes a known goerli transaction signed by ruby eth gem" do
it "decodes a known sepolia transaction signed by ruby eth gem" do

# ref https://goerli.etherscan.io/getRawTx?tx=0x047e319fc8e587a77f6e9a13c30d90b5a741d93e8b35a54b12c91d6149eda359
expected_hex = "0xf880038509c76524008259d894caa29806044a08e533963b2e573c1230a2cd9a2d8718838370f3400095466f6f20426172205275627920457468657265756d2ea0a0133bf9a770032e18a2ce0eda0d8562abbd88920d696d02373e901967f9956da075e6ce3e86db8391524a7dff0331e90c2bf18cedfbd4164f177a86c53e5be4fa"
expected_hash = "0x047e319fc8e587a77f6e9a13c30d90b5a741d93e8b35a54b12c91d6149eda359"
# ref https://sepolia.etherscan.io/getRawTx?tx=0x01fa6584df6326dc503ca809c9c4643cd753ba8ae63473a9994770f403cda447
expected_hex = "0xf884038509c76524008259d894caa29806044a08e533963b2e573c1230a2cd9a2d8718838370f3400095466f6f20426172205275627920457468657265756d8401546d72a0980cf5d1c20ed6a44a57b4ec70301da608247013be59be740e471579a16b9963a053a2e3b95f666c38ec26c0be6105affd23c037c67277ed920aae79f93c020fa6"
expected_hash = "0x01fa6584df6326dc503ca809c9c4643cd753ba8ae63473a9994770f403cda447"
decoded = Tx.decode(expected_hex)
expect(decoded.hex).to eq Util.remove_hex_prefix expected_hex
expect(decoded.hash).to eq Util.remove_hex_prefix expected_hash
Expand Down Expand Up @@ -167,7 +167,7 @@

it "it does not sign a transaction twice" do
expect { legacy.hash }.to raise_error StandardError, "Transaction is not signed!"
expect(testnet.address.to_s).to eq "0x4762119a7249823D18aec7EAB73258B2D5061Dd8"
expect(testnet.address.to_s).to eq "0xC3c8Fd0f04B629c5E2297b79c54DD57b85A721e3"
legacy.sign(testnet)
expect { legacy.sign(testnet) }.to raise_error StandardError, "Transaction is already signed!"
end
Expand Down Expand Up @@ -198,7 +198,7 @@
it "encodes a known goerli transaction" do
expect { legacy.encoded }.to raise_error StandardError, "Transaction is not signed!"
legacy.sign(testnet)
expect(legacy.encoded).to eq "\xF8\x90\x01\x85\tP/\x90\x00\x82TH\x94\xCA\xA2\x98\x06\x04J\b\xE53\x96;.W<\x120\xA2\xCD\x9A-\x88\x01\xB6\x9BK\xA60\xF3N\xA4Lorem Ipsum Ruby Ethereum Test 1-2-3.\xA0\xFBM0\x8F=?\x97p\xF2e.\xF4\x0E\xA86\x9A\xB3r\xE5\x9B\xAD\x81O\xB2'\xFA\xE1\xFD\xFD\xFAM:\xA0f\xC8\xA2\xA2\xA2\xAB\xCD9\e\xAC\x869\x99Z\x10\xF1Tj\x87>\xF5\xB4R\xBF\xE5\xFC6y\x01\xD9\xF4\xAB"
expect(legacy.encoded).to eq "\xF8\x94\x01\x85\tP/\x90\x00\x82TL\x94\xCA\xA2\x98\x06\x04J\b\xE53\x96;.W<\x120\xA2\xCD\x9A-\x88\x01\xB6\x9BK\xA60\xF3N\xA4Lorem Ipsum Ruby Ethereum Test 1-2-3\x84\x01Tmr\xA0\x9Eh\x00\x9D\xBA<\x05MyVM\x82W\x86\xE9Z\xE7t\xF2\xE5\xB2\xF4\xD7_\xA5X\x88=\v#_\x82\xA02\xDCc\t\xDD\xD9)\xF5\xB1\xFC\xE3\xC9\xEC\x04\x13\aR\xF4\n}\xA2\xF2\x82\xE7x\b\xD6\x97\x93\xF6F\xEF"
end
end

Expand All @@ -212,7 +212,7 @@
it "hexes a known goerli transaction" do
expect { legacy.hex }.to raise_error StandardError, "Transaction is not signed!"
legacy.sign(testnet)
expect(legacy.hex).to eq "f890018509502f900082544894caa29806044a08e533963b2e573c1230a2cd9a2d8801b69b4ba630f34ea44c6f72656d20497073756d205275627920457468657265756d205465737420312d322d332ea0fb4d308f3d3f9770f2652ef40ea8369ab372e59bad814fb227fae1fdfdfa4d3aa066c8a2a2a2abcd391bac8639995a10f1546a873ef5b452bfe5fc367901d9f4ab"
expect(legacy.hex).to eq "f894018509502f900082544c94caa29806044a08e533963b2e573c1230a2cd9a2d8801b69b4ba630f34ea44c6f72656d20497073756d205275627920457468657265756d205465737420312d322d338401546d72a09e68009dba3c054d79564d825786e95ae774f2e5b2f4d75fa558883d0b235f82a032dc6309ddd929f5b1fce3c9ec04130752f40a7da2f282e77808d69793f646ef"
end
end

Expand All @@ -226,7 +226,7 @@
it "hashes a known goerli transaction" do
expect { legacy.hash }.to raise_error StandardError, "Transaction is not signed!"
legacy.sign(testnet)
expect(legacy.hash).to eq "1975df4e715ce4af46c604e3fafb763a51cc133a42e43566779b4d5608bb4af1"
expect(legacy.hash).to eq "7613b4de482fcff616e11907d16ddba1aa950a020ec58e99ab28ba0c5926ec53"
end
end

Expand Down Expand Up @@ -300,15 +300,15 @@
-4153010759215853346544872368790226810347211436084119296615430562753409734914,
]
}
subject(:expected_hex) { "f9010c80018259ac8080b8c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000003ea1e26a2119b038eaf9b27e65cdb401502ae7a43d8bfb1368aee2693eb325af9f81244b19304b087b4941a1e892da50bd48dfe1f6d17aad7aff1c87e8481f30395a1595a07b483032affed044e698bf7c43a6fe000000000000000000000000000000000000000000000000000000000000000d4c6f72656d2c20497073756d210000000000000000000000000000000000000026a0b06ef4fc47e80f9fc70143b558dfa31d6dae04661f37715b982718f8185aefa3a032a8b187b43ae4af3755e7158f7cbb9585485e05ffdd38fe3343767a61730026" }
subject(:expected_hash) { "3ac265b9741844e04f9ac8436469393a44d89d6fe20343fc9ea60f0f377db9ec" }
subject(:expected_hex) { "f9010c80018259b88080b8c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000003ea1e26a2119b038eaf9b27e65cdb401502ae7a43d8bfb1368aee2693eb325af9f81244b19304b087b4941a1e892da50bd48dfe1f6d17aad7aff1c87e8481f30395a1595a07b483032affed044e698bf7c43a6fe000000000000000000000000000000000000000000000000000000000000000d4c6f72656d2c20497073756d210000000000000000000000000000000000000026a081bf91ec0984c884c7d8afe094743d30c73e08c6d6c2da497dbb75193dd0cd07a059189d3f14ea3e0eccc6240e019f09d6b277e1525a0aa7e5bdca9e444f6f4630" }
subject(:expected_hash) { "045ef9de4ed1aee2274be36a92db5293063bee674ec46ad94ad4d057250db536" }

it "can create transactions with binary data" do
abi = Abi.encode types, args
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 22_956,
gas_limit: 22_968,
data: abi,
})

Expand All @@ -332,7 +332,7 @@
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 22_956,
gas_limit: 22_968,
data: hex,
})

Expand All @@ -357,12 +357,12 @@
some = Tx.new({
nonce: 0,
gas_price: 1,
gas_limit: 21_208,
gas_limit: 21_210,
data: lorem,
})
some.sign cow
expect(some.hex).to eq "f85880018252d880808d4c6f72656d2c20497073756d2125a08540db1627dd415d4b53f2d0b7835510ab9cfc77ad40a785e7e0dc6ec63cef79a02822730ee77dfddee349d720e3cfa955b38f7ffb9e482e4c15931bb9cca0c33c"
expect(some.hash).to eq "37aa7c93ffcbc92bcd016796ae231ea2ddce5c0daa5f5646784d3cbb9b6cff3b"
expect(some.hex).to eq "f85880018252da80808d4c6f72656d2c20497073756d2125a0121ceae143464734a25416294fd324e8a5a8578bbad84b7044a2f84b2ae0c0e8a00f72e5a58b1c40a9484026137e69a00746d613bd9445d767a7d7a305a2947e2d"
expect(some.hash).to eq "43bbce3dc6bc845bfbf052df40bfbf20086eb6f983c5aacf9a964a0cc6b1c22a"

# expect to match both decoded transaction and decoded abi
other = Tx.decode some.hex
Expand Down
Loading

0 comments on commit 92e6c54

Please sign in to comment.