Skip to content

Commit 4fd1137

Browse files
fix: cherry-pick to 0.52 fix for charging correct gas for new isAuthorizedRaw system contract method (#14193)
Signed-off-by: David S Bakin <[email protected]>
1 parent 7956189 commit 4fd1137

File tree

15 files changed

+631
-311
lines changed

15 files changed

+631
-311
lines changed

hedera-node/hapi-utils/src/main/java/com/hedera/node/app/hapi/utils/ethereum/EthTxSigs.java

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
import com.esaulpaugh.headlong.util.Integers;
2828
import com.google.common.annotations.VisibleForTesting;
2929
import com.google.common.base.MoreObjects;
30-
import com.sun.jna.ptr.IntByReference;
3130
import com.sun.jna.ptr.LongByReference;
32-
import java.math.BigInteger;
3331
import java.nio.ByteBuffer;
3432
import java.util.Arrays;
3533
import org.apache.commons.codec.binary.Hex;
@@ -47,76 +45,6 @@ public static EthTxSigs extractSignatures(EthTxData ethTx) {
4745
return new EthTxSigs(compressedKey, address);
4846
}
4947

50-
public static EthTxData signMessage(EthTxData ethTx, byte[] privateKey) {
51-
byte[] signableMessage = calculateSignableMessage(ethTx);
52-
final LibSecp256k1.secp256k1_ecdsa_recoverable_signature signature =
53-
new LibSecp256k1.secp256k1_ecdsa_recoverable_signature();
54-
LibSecp256k1.secp256k1_ecdsa_sign_recoverable(
55-
CONTEXT, signature, new Keccak.Digest256().digest(signableMessage), privateKey, null, null);
56-
57-
final ByteBuffer compactSig = ByteBuffer.allocate(64);
58-
final IntByReference recId = new IntByReference(0);
59-
LibSecp256k1.secp256k1_ecdsa_recoverable_signature_serialize_compact(
60-
LibSecp256k1.CONTEXT, compactSig, recId, signature);
61-
compactSig.flip();
62-
final byte[] sig = compactSig.array();
63-
64-
// wrap in signature object
65-
final byte[] r = new byte[32];
66-
System.arraycopy(sig, 0, r, 0, 32);
67-
final byte[] s = new byte[32];
68-
System.arraycopy(sig, 32, s, 0, 32);
69-
70-
BigInteger val;
71-
// calulations originate from https://eips.ethereum.org/EIPS/eip-155
72-
if (ethTx.type() == LEGACY_ETHEREUM) {
73-
if (ethTx.chainId() == null || ethTx.chainId().length == 0) {
74-
val = BigInteger.valueOf(27L + recId.getValue());
75-
} else {
76-
val = BigInteger.valueOf(35L + recId.getValue())
77-
.add(new BigInteger(1, ethTx.chainId()).multiply(BigInteger.TWO));
78-
}
79-
} else {
80-
val = null;
81-
}
82-
83-
return new EthTxData(
84-
ethTx.rawTx(),
85-
ethTx.type(),
86-
ethTx.chainId(),
87-
ethTx.nonce(),
88-
ethTx.gasPrice(),
89-
ethTx.maxPriorityGas(),
90-
ethTx.maxGas(),
91-
ethTx.gasLimit(),
92-
ethTx.to(),
93-
ethTx.value(),
94-
ethTx.callData(),
95-
ethTx.accessList(),
96-
(byte) recId.getValue(),
97-
val == null ? null : val.toByteArray(),
98-
r,
99-
s);
100-
}
101-
102-
public static byte[] signMessage(final byte[] messageHash, byte[] privateKey) {
103-
final LibSecp256k1.secp256k1_ecdsa_recoverable_signature signature =
104-
new LibSecp256k1.secp256k1_ecdsa_recoverable_signature();
105-
LibSecp256k1.secp256k1_ecdsa_sign_recoverable(CONTEXT, signature, messageHash, privateKey, null, null);
106-
107-
final ByteBuffer compactSig = ByteBuffer.allocate(64);
108-
final IntByReference recId = new IntByReference(0);
109-
LibSecp256k1.secp256k1_ecdsa_recoverable_signature_serialize_compact(
110-
LibSecp256k1.CONTEXT, compactSig, recId, signature);
111-
compactSig.flip();
112-
final byte[] sig = compactSig.array();
113-
114-
final byte[] result = new byte[65];
115-
System.arraycopy(sig, 0, result, 0, 64);
116-
result[64] = (byte) (recId.getValue() + 27);
117-
return result;
118-
}
119-
12048
public static byte[] calculateSignableMessage(EthTxData ethTx) {
12149
return switch (ethTx.type()) {
12250
case LEGACY_ETHEREUM -> (ethTx.chainId() != null && ethTx.chainId().length > 0)

hedera-node/hapi-utils/src/test/java/com/hedera/node/app/hapi/utils/ethereum/EthTxSigsTest.java

Lines changed: 0 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,9 @@
2424
import static com.hedera.node.app.hapi.utils.ethereum.TestingConstants.TRUFFLE0_PRIVATE_ECDSA_KEY;
2525
import static com.hedera.node.app.hapi.utils.ethereum.TestingConstants.TRUFFLE0_PUBLIC_ECDSA_KEY;
2626
import static com.hedera.node.app.hapi.utils.ethereum.TestingConstants.TRUFFLE1_ADDRESS;
27-
import static com.hedera.node.app.hapi.utils.ethereum.TestingConstants.TRUFFLE1_PRIVATE_ECDSA_KEY;
2827
import static com.hedera.node.app.hapi.utils.ethereum.TestingConstants.ZERO_BYTES;
2928
import static com.hedera.node.app.service.evm.utils.EthSigsUtils.recoverAddressFromPubKey;
3029
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
31-
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
32-
import static org.junit.jupiter.api.Assertions.assertEquals;
33-
import static org.junit.jupiter.api.Assertions.assertNotEquals;
34-
import static org.junit.jupiter.api.Assertions.assertNotNull;
3530
import static org.junit.jupiter.api.Assertions.assertThrows;
3631

3732
import com.swirlds.common.utility.CommonUtils;
@@ -96,207 +91,6 @@ public byte[] nextBytes(final int n) {
9691
return ans;
9792
}
9893

99-
@Test
100-
void signsLegacyUnprotectedNull() {
101-
final var tx = new EthTxData(
102-
null,
103-
LEGACY_ETHEREUM,
104-
null,
105-
1,
106-
TINYBARS_57_IN_WEIBARS,
107-
TINYBARS_2_IN_WEIBARS,
108-
TINYBARS_57_IN_WEIBARS,
109-
1_000_000L,
110-
TRUFFLE1_ADDRESS,
111-
BigInteger.ZERO,
112-
ZERO_BYTES,
113-
ZERO_BYTES,
114-
1,
115-
new byte[0],
116-
new byte[0],
117-
new byte[0]);
118-
119-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
120-
121-
assertArrayEquals(null, signedTx.chainId());
122-
assertArrayEquals(new byte[] {27}, signedTx.v());
123-
assertNotNull(tx.r());
124-
assertNotNull(tx.s());
125-
}
126-
127-
@Test
128-
void signsLegacyUnprotectedZeroChainId() {
129-
final var tx = new EthTxData(
130-
null,
131-
LEGACY_ETHEREUM,
132-
ZERO_BYTES,
133-
1,
134-
TINYBARS_57_IN_WEIBARS,
135-
TINYBARS_2_IN_WEIBARS,
136-
TINYBARS_57_IN_WEIBARS,
137-
1_000_000L,
138-
TRUFFLE1_ADDRESS,
139-
BigInteger.ZERO,
140-
ZERO_BYTES,
141-
ZERO_BYTES,
142-
1,
143-
new byte[0],
144-
new byte[0],
145-
new byte[0]);
146-
147-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
148-
149-
Assertions.assertArrayEquals(ZERO_BYTES, signedTx.chainId());
150-
assertArrayEquals(new byte[] {27}, signedTx.v());
151-
assertNotNull(tx.r());
152-
assertNotNull(tx.s());
153-
}
154-
155-
@Test
156-
void signsEIP2930() {
157-
final var tx = new EthTxData(
158-
null,
159-
EthTxData.EthTransactionType.EIP2930,
160-
ZERO_BYTES,
161-
1,
162-
TINYBARS_57_IN_WEIBARS,
163-
TINYBARS_2_IN_WEIBARS,
164-
TINYBARS_57_IN_WEIBARS,
165-
1_000_000L,
166-
TRUFFLE1_ADDRESS,
167-
BigInteger.ZERO,
168-
ZERO_BYTES,
169-
ZERO_BYTES,
170-
1,
171-
new byte[0],
172-
new byte[0],
173-
new byte[0]);
174-
175-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
176-
177-
assertNotNull(signedTx.r());
178-
assertNotNull(signedTx.s());
179-
}
180-
181-
@Test
182-
void signsEIP1559() {
183-
final var tx = new EthTxData(
184-
null,
185-
EthTxData.EthTransactionType.EIP1559,
186-
ZERO_BYTES,
187-
1,
188-
TINYBARS_57_IN_WEIBARS,
189-
TINYBARS_2_IN_WEIBARS,
190-
TINYBARS_57_IN_WEIBARS,
191-
1_000_000L,
192-
TRUFFLE1_ADDRESS,
193-
BigInteger.ZERO,
194-
ZERO_BYTES,
195-
ZERO_BYTES,
196-
1,
197-
new byte[0],
198-
new byte[0],
199-
new byte[0]);
200-
201-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
202-
203-
assertNotNull(signedTx.r());
204-
assertNotNull(signedTx.s());
205-
}
206-
207-
@Test
208-
void signsLegacyProtected() {
209-
final var tx = new EthTxData(
210-
null,
211-
LEGACY_ETHEREUM,
212-
CHAINID_TESTNET,
213-
1,
214-
TINYBARS_57_IN_WEIBARS,
215-
TINYBARS_2_IN_WEIBARS,
216-
TINYBARS_57_IN_WEIBARS,
217-
1_000_000L,
218-
TRUFFLE1_ADDRESS,
219-
BigInteger.ZERO,
220-
ZERO_BYTES,
221-
ZERO_BYTES,
222-
1,
223-
new byte[0],
224-
new byte[0],
225-
new byte[0]);
226-
227-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
228-
229-
Assertions.assertArrayEquals(CHAINID_TESTNET, signedTx.chainId());
230-
assertArrayEquals(new byte[] {2, 116}, signedTx.v());
231-
}
232-
233-
@Test
234-
void extractAddress() {
235-
final var tx = new EthTxData(
236-
null,
237-
LEGACY_ETHEREUM,
238-
CHAINID_TESTNET,
239-
1,
240-
TINYBARS_57_IN_WEIBARS,
241-
TINYBARS_2_IN_WEIBARS,
242-
TINYBARS_57_IN_WEIBARS,
243-
1_000_000L,
244-
TRUFFLE1_ADDRESS,
245-
BigInteger.ZERO,
246-
ZERO_BYTES,
247-
ZERO_BYTES,
248-
1,
249-
new byte[0],
250-
new byte[0],
251-
new byte[0]);
252-
253-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
254-
255-
final EthTxSigs sigs = EthTxSigs.extractSignatures(signedTx);
256-
257-
Assertions.assertArrayEquals(TRUFFLE0_ADDRESS, sigs.address());
258-
Assertions.assertArrayEquals(TRUFFLE0_PUBLIC_ECDSA_KEY, sigs.publicKey());
259-
}
260-
261-
@Test
262-
void equalsToStringHashCode() {
263-
final var tx = new EthTxData(
264-
null,
265-
LEGACY_ETHEREUM,
266-
CHAINID_TESTNET,
267-
1,
268-
TINYBARS_57_IN_WEIBARS,
269-
TINYBARS_2_IN_WEIBARS,
270-
TINYBARS_57_IN_WEIBARS,
271-
1_000_000L,
272-
TRUFFLE1_ADDRESS,
273-
BigInteger.ZERO,
274-
ZERO_BYTES,
275-
ZERO_BYTES,
276-
1,
277-
new byte[0],
278-
new byte[0],
279-
new byte[0]);
280-
281-
final EthTxData signedTx = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
282-
final EthTxData signedTxAgain = EthTxSigs.signMessage(tx, TRUFFLE0_PRIVATE_ECDSA_KEY);
283-
final EthTxData signedTx1 = EthTxSigs.signMessage(tx, TRUFFLE1_PRIVATE_ECDSA_KEY);
284-
285-
final EthTxSigs sigs = EthTxSigs.extractSignatures(signedTx);
286-
final EthTxSigs sigsAgain = EthTxSigs.extractSignatures(signedTxAgain);
287-
final EthTxSigs sigs1 = EthTxSigs.extractSignatures(signedTx1);
288-
289-
assertEquals(sigs.toString(), sigsAgain.toString());
290-
assertNotEquals(sigs.toString(), sigs1.toString());
291-
292-
assertDoesNotThrow(sigs::hashCode);
293-
assertDoesNotThrow(sigsAgain::hashCode);
294-
assertDoesNotThrow(sigs1::hashCode);
295-
296-
assertEquals(sigs, sigsAgain);
297-
assertNotEquals(sigs, sigs1);
298-
}
299-
30094
@Test
30195
void badSignatureVerification() {
30296
final byte[] allFs = new byte[32];

hedera-node/hedera-smart-contract-service-impl/src/main/java/com/hedera/node/app/service/contract/impl/exec/gas/CustomGasCalculator.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ public long codeDepositGasCost(final int codeSize) {
9090
return 0L;
9191
}
9292

93+
/**
94+
* Gas charge to do a signature verification for an ED key.
95+
*
96+
* Based on the cost of system resources used.
97+
*
98+
* FUTURE: Gas for system contract method calls needs to be a) determined by measurement of
99+
* resources consumed, and b) incorporated into the fee schedule.
100+
*/
101+
public long getEdSignatureVerificationSystemContractGasCost() {
102+
return 1_500_000L;
103+
}
104+
93105
/**
94106
* Logically, would return the gas cost of storing the given number of bytes for the given number of seconds,
95107
* given the relative prices of a byte-hour and a gas unit in tinybar.

0 commit comments

Comments
 (0)