Skip to content

Commit 1e2b0fa

Browse files
Basefee calculation release
- Add methods documentation - Refactor calcBaseFee method - refactor ChainVersion mainNetFisrtBlockNumber for clarity - Delete useless ChainVersion Comparable method - Refactor EIP1559Tests class - Add testCalcBaseFee test All tests are green.
1 parent 06d0361 commit 1e2b0fa

File tree

2 files changed

+105
-97
lines changed

2 files changed

+105
-97
lines changed

Sources/web3swift/Web3/Web3+EIP1559.swift

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import BigInt
1717
public extension Web3 {
1818
func verifyGasLimit(parentGasLimit: BigUInt, currentGasLimit: BigUInt) -> Bool {
1919
var diff = BigInt(parentGasLimit) - BigInt(currentGasLimit)
20-
20+
21+
// make diff positive number
2122
diff = diff < 0 ? diff * -1 : diff
2223

2324
let limit = parentGasLimit / Web3.GasLimitBoundDivisor
@@ -31,55 +32,61 @@ public extension Web3 {
3132
return true
3233
}
3334

34-
/// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
35+
/// Method to check is given block valid EIP-1559 block
36+
///
37+
/// Verifies some header attributes which were changed in EIP-1559
38+
///
3539
/// - gas limit check
3640
/// - basefee check
37-
/// This function make checks that this given block is valid post EIP-1559 block and returns true if it is
38-
/// and thors an error if it isn't.
39-
func verifyEip1559Block(parent: Block, current: Block) -> Bool {
40-
var parentGasLimit = parent.gasLimit
41-
if parent.chainVersion != .London {
42-
parentGasLimit = parent.gasLimit * Web3.ElasticityMultiplier
43-
}
41+
///
42+
/// - Parameters:
43+
/// - parent: Previous Block
44+
/// - current: Current block
45+
/// - Returns: True or false if block is EIP-1559 or not
46+
func isEip1559Block(parent: Block, current: Block) -> Bool {
47+
let parentGasLimit = parent.chainVersion >= .London ? parent.gasLimit : parent.gasLimit * Web3.ElasticityMultiplier
4448

4549
guard verifyGasLimit(parentGasLimit: parentGasLimit, currentGasLimit: current.gasLimit) else { return false }
4650

47-
// ??? In go implementation this field is optional
48-
// if current.baseFeePerGas == nil { throw Web3Error.unknownError }
49-
50-
let expectedBaseFeePerGas = self.calcBaseFee(parent)
51-
52-
// TODO: Make all errors trows more descriptive errors
53-
// ("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d", expectedBaseFee, header.BaseFee, parent.BaseFee, parent.GasUsed)
54-
guard expectedBaseFeePerGas == current.baseFeePerGas else { return false }
51+
guard calcBaseFee(parent) == current.baseFeePerGas else { return false }
5552

5653
return true
5754
}
5855

56+
/// Calculates base fee amount
57+
///
58+
/// You should pass **parent** block to that method to calculate **expected** baseFee for currently
59+
/// processing by blockchain `Block`
60+
///
61+
/// Calculation for current `Block` based on parents block object only
62+
///
63+
/// If passed block isn't `ChainVersion.London` one will return
64+
///
65+
/// - Parameter parent: Parent `Block`
66+
/// - Returns: Amount of expected base fee for current `Block`
5967
func calcBaseFee(_ parent: Block) -> BigUInt {
60-
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
61-
guard parent.chainVersion == .London else { return Web3.InitialBaseFee }
68+
// If given blocks ChainVersion is lower than London — always returns InitialBaseFee
69+
guard parent.chainVersion >= .London else { return Web3.InitialBaseFee }
6270

6371
let parentGasTarget = parent.gasLimit / Web3.ElasticityMultiplier
6472

65-
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
66-
if parent.gasUsed == parentGasTarget {
67-
return parent.baseFeePerGas
68-
69-
} else if parent.gasUsed > parentGasTarget {
73+
if parent.gasUsed > parentGasTarget {
7074
// If the parent block used more gas than its target, the baseFee should increase.
7175
let gasUsedDelta = parent.gasUsed - parentGasTarget
7276
let baseFeePerGasDelta = max(parent.baseFeePerGas * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator, 1)
7377
let expectedBaseFeePerGas = parent.baseFeePerGas + baseFeePerGasDelta
7478

7579
return expectedBaseFeePerGas
76-
} else {
80+
} else if parent.gasUsed < parentGasTarget {
7781
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
7882
let gasUsedDelta = parentGasTarget - parent.gasUsed
7983
let baseFeePerGasDelta = parent.baseFeePerGas * gasUsedDelta / parentGasTarget / Web3.BaseFeeChangeDenominator
8084
let expectedBaseFeePerGas = parent.baseFeePerGas - baseFeePerGasDelta
8185

8286
return expectedBaseFeePerGas
87+
} else {
88+
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
89+
return parent.baseFeePerGas
8390
}
8491
}
8592
}
@@ -135,7 +142,7 @@ public extension Web3 {
135142
/// Block number: 13_773_000
136143
case ArrowGlacier
137144

138-
var blockNumber: BigUInt {
145+
var mainNetFisrtBlockNumber: BigUInt {
139146
switch self {
140147
case .Byzantium: return 4_370_000
141148
case .Constantinople: return 7_280_000
@@ -152,28 +159,26 @@ public extension Web3 {
152159
static func getChainVersion(of block: BigUInt) -> ChainVersion {
153160
// Iterate given block number over each ChainVersion block numbers
154161
// to get the block's ChainVersion.
155-
if block < ChainVersion.Constantinople.blockNumber {
162+
if block < ChainVersion.Constantinople.mainNetFisrtBlockNumber {
156163
return .Byzantium
157164
// ~= means included in a given range
158-
} else if ChainVersion.Constantinople.blockNumber..<ChainVersion.Istanbul.blockNumber ~= block {
165+
} else if ChainVersion.Constantinople.mainNetFisrtBlockNumber..<ChainVersion.Istanbul.mainNetFisrtBlockNumber ~= block {
159166
return .Constantinople
160-
} else if ChainVersion.Istanbul.blockNumber..<ChainVersion.MuirGlacier.blockNumber ~= block {
167+
} else if ChainVersion.Istanbul.mainNetFisrtBlockNumber..<ChainVersion.MuirGlacier.mainNetFisrtBlockNumber ~= block {
161168
return .Istanbul
162-
} else if ChainVersion.MuirGlacier.blockNumber..<ChainVersion.Berlin.blockNumber ~= block {
169+
} else if ChainVersion.MuirGlacier.mainNetFisrtBlockNumber..<ChainVersion.Berlin.mainNetFisrtBlockNumber ~= block {
163170
return .MuirGlacier
164-
} else if ChainVersion.Berlin.blockNumber..<ChainVersion.London.blockNumber ~= block {
171+
} else if ChainVersion.Berlin.mainNetFisrtBlockNumber..<ChainVersion.London.mainNetFisrtBlockNumber ~= block {
165172
return .Berlin
166-
} else if ChainVersion.London.blockNumber..<ChainVersion.ArrowGlacier.blockNumber ~= block {
173+
} else if ChainVersion.London.mainNetFisrtBlockNumber..<ChainVersion.ArrowGlacier.mainNetFisrtBlockNumber ~= block {
167174
return .London
168-
} else if block >= ChainVersion.ArrowGlacier.blockNumber {
175+
} else if block >= ChainVersion.ArrowGlacier.mainNetFisrtBlockNumber {
169176
// Pass to the default return.
170177
}
171178
return .ArrowGlacier
172179
}
173180
}
174181

175182
extension Web3.ChainVersion: Comparable {
176-
public static func < (lhs: Web3.ChainVersion, rhs: Web3.ChainVersion) -> Bool { return lhs.blockNumber < rhs.blockNumber }
177-
178-
public static func <= (lhs: Web3.ChainVersion, rhs: Web3.ChainVersion) -> Bool { return lhs.blockNumber <= rhs.blockNumber }
183+
public static func < (lhs: Web3.ChainVersion, rhs: Web3.ChainVersion) -> Bool { return lhs.mainNetFisrtBlockNumber < rhs.mainNetFisrtBlockNumber }
179184
}

Tests/web3swiftTests/localTests/EIP1559Tests.swift

Lines changed: 64 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,38 @@ import BigInt
55
import web3swift
66

77
class EIP1559Tests: XCTestCase {
8+
let web3 = Web3()
9+
10+
let uselessBlockPart = (
11+
number: BigUInt(12_965_000),
12+
hash: Data(from: "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46")!, // "hash":
13+
parentHash: Data(from: "0x2302e1c0b972d00932deb5dab9eb2982f570597d9d42504c05d9c2147eaf9c88")!, // "parentHash":
14+
nonce: Data(from: "0xfb6e1a62d119228b"), // "nonce":
15+
sha3Uncles: Data(from: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")!, // "sha3Uncles":
16+
receiptsRoot: Data(from: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")!, // "receiptsRoot":
17+
logsBloom: EthereumBloomFilter(Data(from: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!), // "logsBloom":
18+
transactionsRoot: Data(from: "0x3a1b03875115b79539e5bd33fb00d8f7b7cd61929d5a3c574f507b8acf415bee")!, // "transactionsRoot":
19+
stateRoot: Data(from: "0xf1133199d44695dfa8fd1bcfe424d82854b5cebef75bddd7e40ea94cda515bcb")!, // "stateRoot":
20+
miner: EthereumAddress( Data(from: "0x8888f1f195afa192cfee860698584c030f4c9db1")!)!, // "miner":
21+
difficulty: BigUInt(21345678965432), // "difficulty":
22+
totalDifficulty: BigUInt(324567845321), // "totalDifficulty":
23+
size: BigUInt(616), // "size":
24+
extraData: Data(from: "0x")!, // extraData":
25+
gasLimit: BigUInt(3141592), // "gasLimit":
26+
gasUsed: BigUInt(21662), // "gasUsed":
27+
timestamp: Date(), // "timestamp":
28+
transactions: [TransactionInBlock](), // "transactions":
29+
uncles: [Data]() // "uncles":
30+
)
831

932
/// testBlockGasLimits tests the gasLimit checks for blocks both across
1033
/// the EIP-1559 boundary and post-1559 blocks
1134
func testBlockGasLimits() throws {
12-
let uselessBlockPart = (
13-
number: BigUInt(3),
14-
15-
hash: Data(from: "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46")!, // "hash":
16-
parentHash: Data(from: "0x2302e1c0b972d00932deb5dab9eb2982f570597d9d42504c05d9c2147eaf9c88")!, // "parentHash":
17-
// baseFeePerGas: 58713056622, // baseFeePerGas":
18-
nonce: Data(from: "0xfb6e1a62d119228b"), // "nonce":
19-
sha3Uncles: Data(from: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")!, // "sha3Uncles":
20-
receiptsRoot: Data(from: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")!, // "receiptsRoot":
21-
logsBloom: EthereumBloomFilter(Data(from: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")!), // "logsBloom":
22-
transactionsRoot: Data(from: "0x3a1b03875115b79539e5bd33fb00d8f7b7cd61929d5a3c574f507b8acf415bee")!, // "transactionsRoot":
23-
stateRoot: Data(from: "0xf1133199d44695dfa8fd1bcfe424d82854b5cebef75bddd7e40ea94cda515bcb")!, // "stateRoot":
24-
miner: EthereumAddress( Data(from: "0x8888f1f195afa192cfee860698584c030f4c9db1")!)!, // "miner":
25-
difficulty: BigUInt(21345678965432), // "difficulty":
26-
totalDifficulty: BigUInt(324567845321), // "totalDifficulty":
27-
size: BigUInt(616), // "size":
28-
extraData: Data(from: "0x")!, // extraData":
29-
gasLimit: BigUInt(3141592), // "gasLimit":
30-
gasUsed: BigUInt(21662), // "gasUsed":
31-
timestamp: Date(), // "timestamp":
32-
transactions: [TransactionInBlock](), // "transactions":
33-
uncles: [Data]() // "uncles":
34-
)
35-
3635
// [0] - parentGasLimit
3736
// [1] - parentNumber
3837
// [2] - currentGasLimit
3938
// [3] - Should fail or not
40-
let headerArray: [(BigUInt, BigUInt, BigUInt, Bool) ] = [
39+
let headerArray: [(BigUInt, BigUInt, BigUInt, Bool)] = [
4140
// Transitions from non-london to london
4241
(10_000_000, 12_964_999, 20_000_000, true), // No change
4342
(10_000_000, 12_964_999, 20_019_530, true), // Upper limit
@@ -55,9 +54,9 @@ class EIP1559Tests: XCTestCase {
5554
(40_000_000, 12_965_000, 40_039_062, false), // Upper limit +1
5655
(40_000_000, 12_965_000, 39_960_939, true), // lower limit
5756
(40_000_000, 12_965_000, 39_960_938, false), // Lower limit -1
58-
]
57+
]
5958

60-
try headerArray.forEach { (touple: (parentGasLimit: BigUInt, parentNumber: BigUInt, currentGasLimit: BigUInt, isOk: Bool)) in
59+
headerArray.forEach { (touple: (parentGasLimit: BigUInt, parentNumber: BigUInt, currentGasLimit: BigUInt, is1559: Bool)) in
6160
let parent = Block(number: touple.parentNumber,
6261
hash: uselessBlockPart.hash,
6362
parentHash: uselessBlockPart.parentHash,
@@ -100,51 +99,55 @@ class EIP1559Tests: XCTestCase {
10099
transactions: uselessBlockPart.transactions,
101100
uncles: uselessBlockPart.uncles)
102101

103-
let web3 = Web3()
104-
105-
if touple.isOk {
106-
XCTAssertTrue(web3.verifyEip1559Block(parent: parent, current: current),
102+
if touple.is1559 {
103+
XCTAssertTrue(web3.isEip1559Block(parent: parent, current: current),
107104
"Shoult not fail, got parent: \(parent.gasLimit), current: \(current.gasLimit)")
108105
} else {
109-
XCTAssertFalse(web3.verifyEip1559Block(parent: parent, current: current),
106+
XCTAssertFalse(web3.isEip1559Block(parent: parent, current: current),
110107
"Should fail, got parent: \(parent.gasLimit), current: \(current.gasLimit)")
111108
}
112109
}
113110
}
114111

115112
/// testCalcBaseFee assumes all blocks are 1559-blocks
116113
func testCalcBaseFee() throws {
114+
// [0] - parentBaseFee
115+
// [1] - parentNumber
116+
// [2] - parentGasLimit
117+
// [3] - parentGasUsed
118+
// [4] - expectedBaseFee
119+
let headerArray: [(BigUInt, BigUInt, BigUInt, BigUInt, BigUInt)] = [
120+
(Web3.InitialBaseFee, 12_964_999, 20000000, 10000000, Web3.InitialBaseFee), // parent is not London
121+
(Web3.InitialBaseFee, 12_965_000, 20000000, 10000000, Web3.InitialBaseFee), // current == target
122+
(Web3.InitialBaseFee, 12_965_000, 20000000, 9000000, 987500000), // current below target
123+
(Web3.InitialBaseFee, 12_965_000, 20000000, 11000000, 1012500000), // current above target
124+
]
125+
126+
headerArray.forEach { (touple: (parentBaseFee: BigUInt, parentNumber: BigUInt, parentGasLimit: BigUInt, parentGasUsed: BigUInt, expectedBaseFee: BigUInt)) in
127+
let parent = Block(number: touple.parentNumber,
128+
hash: uselessBlockPart.hash,
129+
parentHash: uselessBlockPart.parentHash,
130+
nonce: uselessBlockPart.nonce,
131+
sha3Uncles: uselessBlockPart.sha3Uncles,
132+
logsBloom: uselessBlockPart.logsBloom,
133+
transactionsRoot: uselessBlockPart.transactionsRoot,
134+
stateRoot: uselessBlockPart.stateRoot,
135+
receiptsRoot: uselessBlockPart.receiptsRoot,
136+
miner: uselessBlockPart.miner,
137+
difficulty: uselessBlockPart.difficulty,
138+
totalDifficulty: uselessBlockPart.totalDifficulty,
139+
extraData: uselessBlockPart.extraData,
140+
size: uselessBlockPart.size,
141+
gasLimit: touple.parentGasLimit,
142+
gasUsed: touple.parentGasUsed,
143+
baseFeePerGas: Web3.InitialBaseFee,
144+
timestamp: uselessBlockPart.timestamp,
145+
transactions: uselessBlockPart.transactions,
146+
uncles: uselessBlockPart.uncles)
117147

118-
}
119-
120-
121-
122-
}
148+
let calculatedBaseFee = web3.calcBaseFee(parent)
123149

124-
/*
125-
// TestCalcBaseFee assumes all blocks are 1559-blocks
126-
func TestCalcBaseFee(t *testing.T) {
127-
tests := []struct {
128-
parentBaseFee int64
129-
parentGasLimit uint64
130-
parentGasUsed uint64
131-
expectedBaseFee int64
132-
}{
133-
{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
134-
{params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target
135-
{params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target
136-
}
137-
for i, test := range tests {
138-
parent := &types.Header{
139-
Number: common.Big32,
140-
GasLimit: test.parentGasLimit,
141-
GasUsed: test.parentGasUsed,
142-
BaseFee: big.NewInt(test.parentBaseFee),
143-
}
144-
if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 {
145-
t.Errorf("test %d: have %d want %d, ", i, have, want)
150+
XCTAssertEqual(calculatedBaseFee, touple.expectedBaseFee, "Base fee calculation fails: should be \(touple.expectedBaseFee), got: \(calculatedBaseFee)")
146151
}
147152
}
148153
}
149-
150-
*/

0 commit comments

Comments
 (0)