Skip to content

Commit 47fc351

Browse files
committed
merge devnet-ready
2 parents dbc7fb5 + c797cd1 commit 47fc351

File tree

34 files changed

+1193
-948
lines changed

34 files changed

+1193
-948
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ sp-keystore = { git = "https://github.com/paritytech/polkadot-sdk.git", tag = "p
274274
w3f-bls = { git = "https://github.com/opentensor/bls", branch = "fix-no-std", default-features = false }
275275
ark-crypto-primitives = { version = "0.4.0", default-features = false }
276276
ark-scale = { version = "0.0.11", default-features = false }
277-
sp-ark-bls12-381 = { git = "https://github.com/paritytech/substrate-curves", default-features = false }
277+
sp-ark-bls12-381 = { git = "https://github.com/paritytech/arkworks-substrate", package = "sp-ark-bls12-381", default-features = false }
278278
ark-bls12-381 = { version = "0.4.0", default-features = false }
279279
ark-serialize = { version = "0.4.0", default-features = false }
280280
ark-ff = { version = "0.4.0", default-features = false }
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
interface ISR25519Verify {
5+
function verify(
6+
bytes32 message,
7+
bytes32 publicKey,
8+
bytes32 r,
9+
bytes32 s
10+
) external pure returns (bool);
11+
}
12+
13+
interface IED25519Verify {
14+
function verify(
15+
bytes32 message,
16+
bytes32 publicKey,
17+
bytes32 r,
18+
bytes32 s
19+
) external pure returns (bool);
20+
}
21+
22+
contract PrecompileGas {
23+
address constant IED25519VERIFY_ADDRESS =
24+
0x0000000000000000000000000000000000000402;
25+
address constant ISR25519VERIFY_ADDRESS =
26+
0x0000000000000000000000000000000000000403;
27+
IED25519Verify constant ed25519 = IED25519Verify(IED25519VERIFY_ADDRESS);
28+
ISR25519Verify constant sr25519 = ISR25519Verify(ISR25519VERIFY_ADDRESS);
29+
30+
event Log(string message);
31+
32+
bytes32 message =
33+
0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;
34+
bytes32 publicKey =
35+
0x0000000000000000000000000000000000000000000000000000000000000000;
36+
bytes32 r =
37+
0x0000000000000000000000000000000000000000000000000000000000000000;
38+
bytes32 s =
39+
0x0000000000000000000000000000000000000000000000000000000000000000;
40+
41+
/**
42+
* @notice Call the precompile using hardcoded signature data
43+
* @param iterations Number of times to call the precompile
44+
*/
45+
function callED25519(uint64 iterations) external {
46+
for (uint64 i = 0; i < iterations; i++) {
47+
ed25519.verify(message, publicKey, r, s);
48+
}
49+
emit Log("callED25519");
50+
}
51+
52+
/**
53+
* @notice Call the precompile using hardcoded signature data
54+
* @param iterations Number of times to call the precompile
55+
*/
56+
function callSR25519(uint64 iterations) external {
57+
for (uint64 i = 0; i < iterations; i++) {
58+
sr25519.verify(message, publicKey, r, s);
59+
}
60+
emit Log("callSR25519");
61+
}
62+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
export const PrecompileGas_CONTRACT_ABI = [
3+
{
4+
"anonymous": false,
5+
"inputs": [
6+
{
7+
"indexed": false,
8+
"internalType": "string",
9+
"name": "message",
10+
"type": "string"
11+
}
12+
],
13+
"name": "Log",
14+
"type": "event"
15+
},
16+
{
17+
"inputs": [
18+
{
19+
"internalType": "uint64",
20+
"name": "iterations",
21+
"type": "uint64"
22+
}
23+
],
24+
"name": "callED25519",
25+
"outputs": [],
26+
"stateMutability": "nonpayable",
27+
"type": "function"
28+
},
29+
{
30+
"inputs": [
31+
{
32+
"internalType": "uint64",
33+
"name": "iterations",
34+
"type": "uint64"
35+
}
36+
],
37+
"name": "callSR25519",
38+
"outputs": [],
39+
"stateMutability": "nonpayable",
40+
"type": "function"
41+
}
42+
]
43+
44+
export const PrecompileGas_CONTRACT_BYTECODE = "60806040527f1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef5f1b5f555f5f1b6001555f5f1b6002555f5f1b6003553480156045575f5ffd5b5061048b806100535f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806356554a5714610038578063bd9cac2b14610054575b5f5ffd5b610052600480360381019061004d919061028f565b610070565b005b61006e6004803603810190610069919061028f565b61015f565b005b5f5f90505b8167ffffffffffffffff168167ffffffffffffffff1610156101265761040373ffffffffffffffffffffffffffffffffffffffff1663869adcb95f546001546002546003546040518563ffffffff1660e01b81526004016100d994939291906102d2565b602060405180830381865afa1580156100f4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610118919061034a565b508080600101915050610075565b507fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab604051610154906103cf565b60405180910390a150565b5f5f90505b8167ffffffffffffffff168167ffffffffffffffff1610156102155761040273ffffffffffffffffffffffffffffffffffffffff1663869adcb95f546001546002546003546040518563ffffffff1660e01b81526004016101c894939291906102d2565b602060405180830381865afa1580156101e3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610207919061034a565b508080600101915050610164565b507fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab60405161024390610437565b60405180910390a150565b5f5ffd5b5f67ffffffffffffffff82169050919050565b61026e81610252565b8114610278575f5ffd5b50565b5f8135905061028981610265565b92915050565b5f602082840312156102a4576102a361024e565b5b5f6102b18482850161027b565b91505092915050565b5f819050919050565b6102cc816102ba565b82525050565b5f6080820190506102e55f8301876102c3565b6102f260208301866102c3565b6102ff60408301856102c3565b61030c60608301846102c3565b95945050505050565b5f8115159050919050565b61032981610315565b8114610333575f5ffd5b50565b5f8151905061034481610320565b92915050565b5f6020828403121561035f5761035e61024e565b5b5f61036c84828501610336565b91505092915050565b5f82825260208201905092915050565b7f63616c6c535232353531390000000000000000000000000000000000000000005f82015250565b5f6103b9600b83610375565b91506103c482610385565b602082019050919050565b5f6020820190508181035f8301526103e6816103ad565b9050919050565b7f63616c6c454432353531390000000000000000000000000000000000000000005f82015250565b5f610421600b83610375565b915061042c826103ed565b602082019050919050565b5f6020820190508181035f83015261044e81610415565b905091905056fea26469706673582212202addcdae9c59ee78157cddedc3148678edf455132bdfc62347f85e7c660b4d2164736f6c634300081e0033"

contract-tests/src/substrate.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ export function getRandomSubstrateKeypair() {
7676
return hdkdKeyPair
7777
}
7878

79-
export async function getBalance(api: TypedApi<typeof devnet>) {
80-
const value = await api.query.Balances.Account.getValue("")
81-
return value
79+
export async function getBalance(api: TypedApi<typeof devnet>, ss58Address: string) {
80+
const value = await api.query.System.Account.getValue(ss58Address)
81+
return value.data.free
8282
}
8383

8484
export async function getNonce(api: TypedApi<typeof devnet>, ss58Address: string): Promise<number> {
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import * as assert from "assert";
2+
import { generateRandomEthersWallet, getPublicClient } from "../src/utils";
3+
import { ETH_LOCAL_URL } from "../src/config";
4+
import { getBalance, getDevnetApi } from "../src/substrate";
5+
import { forceSetBalanceToEthAddress } from "../src/subtensor";
6+
import { PrecompileGas_CONTRACT_ABI, PrecompileGas_CONTRACT_BYTECODE } from "../src/contracts/precompileGas";
7+
import { ethers } from "ethers";
8+
import { TypedApi } from "polkadot-api";
9+
import { devnet } from "@polkadot-api/descriptors";
10+
import { disableWhiteListCheck } from "../src/subtensor";
11+
import { convertH160ToSS58, convertPublicKeyToSs58 } from "../src/address-utils";
12+
13+
describe("SR25519 ED25519 Precompile Gas Test", () => {
14+
const wallet = generateRandomEthersWallet();
15+
let api: TypedApi<typeof devnet>;
16+
17+
// scope of precompile gas usage for sr25519 and ed25519
18+
const minPrecompileGas = BigInt(6000);
19+
const maxPrecompileGas = BigInt(10000);
20+
21+
before(async () => {
22+
api = await getDevnetApi();
23+
await forceSetBalanceToEthAddress(api, wallet.address);
24+
await disableWhiteListCheck(api, true);
25+
});
26+
27+
it("Can deploy and call attackHardcoded", async () => {
28+
const fee = await api.query.BaseFee.BaseFeePerGas.getValue()
29+
assert.ok(fee[0] > 1000000000);
30+
const baseFee = BigInt(fee[0]) / BigInt(1000000000);
31+
console.log("Base fee per gas:", baseFee);
32+
33+
const contractFactory = new ethers.ContractFactory(PrecompileGas_CONTRACT_ABI, PrecompileGas_CONTRACT_BYTECODE, wallet);
34+
const contractDeploy = await contractFactory.deploy();
35+
36+
const result = await contractDeploy.waitForDeployment();
37+
console.log("Contract deployed to:", result.target);
38+
39+
40+
let oneIterationGas = BigInt(0);
41+
42+
for (const iter of [1, 11, 101]) {
43+
const balanceBefore = await getBalance(api, convertH160ToSS58(wallet.address));
44+
const contract = new ethers.Contract(result.target, PrecompileGas_CONTRACT_ABI, wallet);
45+
const iterations = iter;
46+
const tx = await contract.callED25519(iterations)
47+
await tx.wait()
48+
49+
const balanceAfter = await getBalance(api, convertH160ToSS58(wallet.address));
50+
assert.ok(balanceAfter < balanceBefore);
51+
52+
const usedGas = balanceBefore - balanceAfter;
53+
if (iterations === 1) {
54+
oneIterationGas = usedGas;
55+
continue;
56+
}
57+
58+
assert.ok(usedGas >= oneIterationGas);
59+
60+
const precompileUsedGas = BigInt(usedGas - oneIterationGas);
61+
assert.ok(precompileUsedGas >= minPrecompileGas * BigInt(iterations - 1) * baseFee);
62+
assert.ok(precompileUsedGas <= maxPrecompileGas * BigInt(iterations - 1) * baseFee);
63+
}
64+
65+
for (const iter of [1, 11, 101]) {
66+
const balanceBefore = await getBalance(api, convertH160ToSS58(wallet.address));
67+
const contract = new ethers.Contract(result.target, PrecompileGas_CONTRACT_ABI, wallet);
68+
const iterations = iter;
69+
const tx = await contract.callSR25519(iterations)
70+
await tx.wait()
71+
72+
const balanceAfter = await getBalance(api, convertH160ToSS58(wallet.address));
73+
assert.ok(balanceAfter < balanceBefore);
74+
75+
const usedGas = balanceBefore - balanceAfter;
76+
if (iterations === 1) {
77+
oneIterationGas = usedGas;
78+
continue;
79+
}
80+
81+
assert.ok(usedGas >= oneIterationGas);
82+
83+
const precompileUsedGas = BigInt(usedGas - oneIterationGas);
84+
assert.ok(precompileUsedGas >= minPrecompileGas * BigInt(iterations - 1) * baseFee);
85+
assert.ok(precompileUsedGas <= maxPrecompileGas * BigInt(iterations - 1) * baseFee);
86+
}
87+
});
88+
});

0 commit comments

Comments
 (0)