1616
1717import static org .assertj .core .api .Assertions .assertThat ;
1818
19+ import org .hyperledger .besu .datatypes .AccessListEntry ;
1920import org .hyperledger .besu .ethereum .core .Transaction ;
21+ import org .hyperledger .besu .ethereum .rlp .BytesValueRLPOutput ;
2022import org .hyperledger .besu .ethereum .rlp .RLP ;
2123import org .hyperledger .besu .evm .gascalculator .FrontierGasCalculator ;
2224import org .hyperledger .besu .evm .gascalculator .GasCalculator ;
2325import org .hyperledger .besu .evm .gascalculator .IstanbulGasCalculator ;
26+ import org .hyperledger .besu .evm .gascalculator .PragueGasCalculator ;
27+ import org .hyperledger .besu .evm .gascalculator .ShanghaiGasCalculator ;
2428
29+ import java .util .List ;
2530import java .util .stream .Stream ;
2631
2732import org .apache .tuweni .bytes .Bytes ;
33+ import org .apache .tuweni .bytes .Bytes32 ;
2834import org .assertj .core .api .Assertions ;
2935import org .junit .jupiter .api .Test ;
3036import org .junit .jupiter .params .ParameterizedTest ;
@@ -36,6 +42,8 @@ public class IntrinsicGasTest {
3642 public static Stream <Arguments > data () {
3743 final GasCalculator frontier = new FrontierGasCalculator ();
3844 final GasCalculator istanbul = new IstanbulGasCalculator ();
45+ final GasCalculator shanghai = new ShanghaiGasCalculator ();
46+ final GasCalculator prague = new PragueGasCalculator ();
3947 return Stream .of (
4048 // EnoughGAS
4149 Arguments .of (
@@ -81,16 +89,36 @@ public static Stream<Arguments> data() {
8189 Arguments .of (
8290 istanbul ,
8391 21116L ,
84- "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" ));
92+ "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" ),
93+ // CallData Gas Increase
94+ Arguments .of (
95+ prague ,
96+ 21290L ,
97+ "0xf87c80018261a894095e7baea6a6c7c4c2dfeb977efac326af552d870a9d00000000000000000000000000000000000000000000000000000000001ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804" ),
98+ // AccessList
99+ Arguments .of (
100+ shanghai ,
101+ 25300L ,
102+ "0x01f89a018001826a4094095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f794a95e7baea6a6c7c4c2dfeb977efac326af552d87e1a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80a05cbd172231fc0735e0fb994dd5b1a4939170a260b36f0427a8a80866b063b948a07c230f7f578dd61785c93361b9871c0706ebfa6d06e3f4491dc9558c5202ed36" ));
85103 }
86104
87105 @ ParameterizedTest
88106 @ MethodSource ("data" )
89107 public void validateGasCost (
90108 final GasCalculator gasCalculator , final long expectedGas , final String txRlp ) {
91- Transaction t = Transaction .readFrom (RLP .input (Bytes .fromHexString (txRlp )));
109+ Bytes rlp = Bytes .fromHexString (txRlp );
110+
111+ // non-frontier transactions need to be opaque for parsing to work
112+ if (rlp .get (0 ) > 0 ) {
113+ final BytesValueRLPOutput output = new BytesValueRLPOutput ();
114+ output .writeBytes (rlp );
115+ rlp = output .encoded ();
116+ }
117+
118+ Transaction t = Transaction .readFrom (RLP .input (rlp ));
92119 Assertions .assertThat (
93- gasCalculator .transactionIntrinsicGasCost (t .getPayload (), t .isContractCreation ()))
120+ gasCalculator .transactionIntrinsicGasCost (
121+ t .getPayload (), t .isContractCreation (), evmGasUsed (gasCalculator , t )))
94122 .isEqualTo (expectedGas );
95123 }
96124
@@ -100,4 +128,21 @@ void dryRunDetector() {
100128 .withFailMessage ("This test is here so gradle --dry-run executes this class" )
101129 .isTrue ();
102130 }
131+
132+ long evmGasUsed (final GasCalculator gasCalculator , final Transaction transaction ) {
133+ final List <AccessListEntry > accessListEntries = transaction .getAccessList ().orElse (List .of ());
134+
135+ int accessListStorageCount = 0 ;
136+ for (final var entry : accessListEntries ) {
137+ final List <Bytes32 > storageKeys = entry .storageKeys ();
138+ accessListStorageCount += storageKeys .size ();
139+ }
140+ final long accessListGas =
141+ gasCalculator .accessListGasCost (accessListEntries .size (), accessListStorageCount );
142+
143+ final long codeDelegationGas =
144+ gasCalculator .delegateCodeGasCost (transaction .codeDelegationListSize ());
145+
146+ return accessListGas + codeDelegationGas ;
147+ }
103148}
0 commit comments