Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start chain using genesis config #55

Merged
merged 5 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions e2e/__snapshots__/genesis-provider.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Vitest Snapshot v1

exports[`genesis provider works > handles tx 1`] = `
{
"consumers": 0,
"data": {
"feeFrozen": 0,
"free": 1000000000000000,
"miscFrozen": 0,
"reserved": 0,
},
"nonce": 0,
"providers": 0,
"sufficients": 0,
}
`;

exports[`genesis provider works > handles tx 2`] = `
{
"consumers": 0,
"data": {
"feeFrozen": 0,
"free": 899981152759869,
"miscFrozen": 0,
"reserved": 0,
},
"nonce": 1,
"providers": 0,
"sufficients": 0,
}
`;

exports[`genesis provider works > handles tx 3`] = `
{
"consumers": 0,
"data": {
"feeFrozen": 0,
"free": 100000000000000,
"miscFrozen": 0,
"reserved": 0,
},
"nonce": 0,
"providers": 1,
"sufficients": 0,
}
`;
38 changes: 38 additions & 0 deletions e2e/genesis-provider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest'

import { api, chain, dev, env, expectJson, setupApi, testingPairs } from './helper'

setupApi(env.mandalaGenesis)

describe('genesis provider works', () => {
it('build blocks', async () => {
expect(await dev.newBlock()).toMatchInlineSnapshot(
'"0xcacc274d53b81070033e1b14b4162917be2754ecffaa31943cff06c39d2a8720"'
)
const block = await chain.getBlock('0xcacc274d53b81070033e1b14b4162917be2754ecffaa31943cff06c39d2a8720')
expect(block).toBeTruthy
expect(block?.number).toBe(1)
})

it('handles tx', async () => {
await dev.newBlock()

const properties = await chain.api.chainProperties
const { test1, test2 } = testingPairs(properties.ss58Format)

await dev.setStorages({
System: {
Account: [[[test1.address], { data: { free: 1000 * 1e12 } }]],
},
})

await expectJson(api.query.system.account(test1.address)).toMatchSnapshot()

await api.tx.currencies.transferNativeCurrency(test2.address, 100 * 1e12).signAndSend(test1)

await dev.newBlock()

await expectJson(api.query.system.account(test1.address)).toMatchSnapshot()
await expectJson(api.query.system.account(test2.address)).toMatchSnapshot()
})
})
25 changes: 18 additions & 7 deletions e2e/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import { beforeAll, beforeEach, expect, vi } from 'vitest'
import { Api } from '../src/api'
import { Blockchain } from '../src/blockchain'
import { BuildBlockMode } from '../src/blockchain/txpool'
import { GenesisProvider } from '../src/genesis-provider'
import { InherentProviders, SetTimestamp, SetValidationData } from '../src/blockchain/inherents'
import { ProviderInterface } from '@polkadot/rpc-provider/types'
import { StorageValues } from '../src/utils/set-storage'
import { TaskManager } from '../src/task'
import { createServer } from '../src/server'
import { handler } from '../src/rpc'

export type SetupOption = {
endpoint: string
blockHash: string
endpoint?: string
blockHash?: string
mockSignatureHost?: boolean
allowUnresolvedImports?: boolean
genesis?: string
}

export const env = {
Expand All @@ -28,10 +31,18 @@ export const env = {
endpoint: 'wss://rococo-rpc.polkadot.io',
blockHash: '0x5269cf7f5b15fbc3a881987f014d5ecee5cfcc5c05a4b7c1cb8db550f22147e9',
},
mandalaGenesis: {
genesis: 'https://raw.githubusercontent.com/AcalaNetwork/Acala/master/resources/mandala-dist.json',
},
}

const setupAll = async ({ endpoint, blockHash, mockSignatureHost, allowUnresolvedImports }: SetupOption) => {
const wsProvider = new WsProvider(endpoint)
const setupAll = async ({ endpoint, blockHash, mockSignatureHost, allowUnresolvedImports, genesis }: SetupOption) => {
let wsProvider: ProviderInterface
if (genesis) {
wsProvider = await GenesisProvider.fromUrl(genesis)
} else {
wsProvider = new WsProvider(endpoint)
}
const api = new Api(wsProvider, { SetEvmOrigin: { payload: {}, extrinsic: {} } })

await api.isReady
Expand All @@ -55,7 +66,7 @@ const setupAll = async ({ endpoint, blockHash, mockSignatureHost, allowUnresolve
buildBlockMode: BuildBlockMode.Manual,
inherentProvider: inherents,
header: {
hash: blockHash,
hash: blockHash || (await api.getBlockHash(0)),
number: Number(header.number),
},
})
Expand Down Expand Up @@ -164,8 +175,8 @@ export const mockCallback = () => {

export const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

export const testingPairs = () => {
const keyring = new Keyring({ type: 'ed25519' }) // cannot use sr25519 as it is non determinstic
export const testingPairs = (ss58Format?: number) => {
const keyring = new Keyring({ type: 'ed25519', ss58Format }) // cannot use sr25519 as it is non determinstic
const alice = keyring.addFromUri('//Alice')
const bob = keyring.addFromUri('//Bob')
const charlie = keyring.addFromUri('//Charlie')
Expand Down
11 changes: 11 additions & 0 deletions executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ pub async fn get_runtime_version(code: &str) -> Result<JsValue, JsValue> {
Ok(result)
}

#[wasm_bindgen]
pub async fn calculate_state_root(entries: JsValue) -> Result<JsValue, JsValue> {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
_ = console_log::init_with_level(log::Level::Debug);

let entries = serde_wasm_bindgen::from_value::<Vec<(HexString, HexString)>>(entries)?;
let hash = task::Task::calculate_state_root(entries);

Ok(hash.to_string().into())
}

#[wasm_bindgen]
pub async fn run_task(task_id: u32, ws_url: &str) -> Result<(), JsValue> {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
Expand Down
55 changes: 22 additions & 33 deletions executor/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ pub struct TaskCall {
#[derive(Serialize, Deserialize, Debug)]
pub enum Task {
Call(TaskCall),
CalculateStateRoot {
entries: Vec<(HexString, HexString)>,
},
}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -87,7 +84,6 @@ pub struct CallResponse {
#[derive(Serialize, Deserialize, Debug)]
pub enum TaskResponse {
Call(CallResponse),
CalculateStateRoot(HexString),
Error(String),
}

Expand All @@ -104,9 +100,6 @@ impl Task {
) -> Result<TaskResponse, jsonrpsee::core::Error> {
let resp = match self {
Task::Call(call) => Task::call(task_id, client, call).await,
Task::CalculateStateRoot { entries } => {
Task::calculate_state_root(task_id, client, entries).await
}
}?;

client.task_result(task_id, &resp).await?;
Expand Down Expand Up @@ -224,32 +217,6 @@ impl Task {
})
}))
}

async fn calculate_state_root(
_task_id: u32,
_client: &Client,
entries: Vec<(HexString, HexString)>,
) -> Result<TaskResponse, jsonrpsee::core::Error> {
let mut calc = root_merkle_value(None);
let map = entries
.into_iter()
.map(|(k, v)| (k.0, v.0))
.collect::<BTreeMap<Vec<u8>, Vec<u8>>>();
loop {
match calc {
RootMerkleValueCalculation::Finished { hash, .. } => {
return Ok(TaskResponse::CalculateStateRoot(HexString(hash.to_vec())));
}
RootMerkleValueCalculation::AllKeys(req) => {
calc = req.inject(map.keys().map(|k| k.iter().cloned()));
}
RootMerkleValueCalculation::StorageValue(req) => {
let key = req.key().collect::<Vec<u8>>();
calc = req.inject(TrieEntryVersion::V0, map.get(&key));
}
}
}
}
}

#[allow(unused)]
Expand Down Expand Up @@ -304,6 +271,28 @@ impl Task {

Ok(RuntimeVersion::new(core_version))
}

pub fn calculate_state_root(entries: Vec<(HexString, HexString)>) -> HexString {
let mut calc = root_merkle_value(None);
let map = entries
.into_iter()
.map(|(k, v)| (k.0, v.0))
.collect::<BTreeMap<Vec<u8>, Vec<u8>>>();
loop {
match calc {
RootMerkleValueCalculation::Finished { hash, .. } => {
return HexString(hash.to_vec());
}
RootMerkleValueCalculation::AllKeys(req) => {
calc = req.inject(map.keys().map(|k| k.iter().cloned()));
}
RootMerkleValueCalculation::StorageValue(req) => {
let key = req.key().collect::<Vec<u8>>();
calc = req.inject(TrieEntryVersion::V0, map.get(&key));
}
}
}
}
}

#[test]
Expand Down
23 changes: 12 additions & 11 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,31 +88,32 @@ export class Api {
}

async getMetadata(hash?: string) {
return this.#provider.send<string>('state_getMetadata', [hash])
return this.#provider.send<string>('state_getMetadata', hash ? [hash] : [])
}

async getBlockHash(blockNumber?: number) {
return this.#provider.send<string>('chain_getBlockHash', [blockNumber])
return this.#provider.send<string>('chain_getBlockHash', Number.isInteger(blockNumber) ? [blockNumber] : [])
}

async getHeader(hash?: string) {
return this.#provider.send<Header>('chain_getHeader', [hash])
return this.#provider.send<Header>('chain_getHeader', hash ? [hash] : [])
}

async getBlock(hash?: string) {
return this.#provider.send<SignedBlock>('chain_getBlock', [hash])
return this.#provider.send<SignedBlock>('chain_getBlock', hash ? [hash] : [])
}

async getStorage(key: string, hash?: string) {
return this.#provider.send<string>(hash ? 'state_getStorageAt' : 'state_getStorage', [key, hash])
if (hash) {
return this.#provider.send<string>('state_getStorageAt', [key, hash])
}
return this.#provider.send<string>('state_getStorage', [key])
}

async getKeysPaged(prefix: string, pageSize: number, startKey: string, hash?: string) {
return this.#provider.send<string[]>(hash ? 'state_getKeysPagedAt' : 'state_getKeysPaged', [
prefix,
pageSize,
startKey,
hash,
])
if (hash) {
return this.#provider.send<string[]>('state_getKeysPagedAt', [prefix, pageSize, startKey, hash])
}
return this.#provider.send<string[]>('state_getKeysPaged', [prefix, pageSize, startKey])
}
}
51 changes: 42 additions & 9 deletions src/blockchain/inherents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ export class SetTimestamp implements InherentProvider {
}
}

const MOCK_VALIDATION_DATA = {
validationData: {
relayParentNumber: 1000,
relayParentStorageRoot: '0x49416764844ff0d8bad851e8abe686dff9dd2de78621180ef8e9f99bb7a480f1',
maxPovSize: 5242880,
},
relayChainState: {
trieNodes: [
'0x5f04b49d95320d9021994c850f25b8e385f902000030000080000008000000000010000000100005000000050000000a0000000a000000000050000000100000e8764817000000040000000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000400000000001000b0040000000000000000000014000000040000000400000000000000010100000000060000006400000002000000c8000000020000001900000000000000020000000200000000c817a804000000',
'0x80011080ace5323aee784b03389c0e2cc68d81973f8fa26d395f333ecad7399271c781e1808e5db75be813c05205986cbd6fdede707a4d26816063a41eb42ebc262c734fad',
'0x8004648086a9239b72237f5bf119e2a880c32f5866460632700509cb874c60f67fe815ea80f6f6801e4b41e2e6d8ec194dba122bfb9eb33feb2545ef5144cea79551f7cc5280c629a7e712d763fe83b35d2a082430af6737a89f23219c0eb3051c83bc5af5ad80fed5ecd6097308a6540f8cf31aeaad186e6898d2ecc0e623767c521c70e39953',
'0x800804809f3ada68c357b5e0a3ebb39ef181acfa9943af4725c244330a4b2c60837612e88082ad3fbdf392429afeacc70177704b760bb145547c1f152e1fcf651916b43820',
'0x8008208042793f557c1d003b647e2eda79c2b5088c7d8cab2e82c1dcc87f4343cca91ae4485ead6eef5c4b1c68eaa71ea17a02d9de0400',
'0x80210280de38445d825563f8e218255a417c16971afa85b4f2ef18fbe08fbc5b976dc0d6801a2ff24096295cfccf1adda80b8dfffe380b9f3b54d7a3cdb67864a4655e62968022a699b2cc90a6654c84163d2a498506b192afe7cd9777227e5288e8ff069c0f',
'0x80400180ebebd1a1cd0bbc6714b7fb0ac854cca5a4c4e34e69485da48be3c8087b56e09b80128645c79ca6581c248a412fd7b8bc532a187600e6e1cc20c915538ba4df6a79',
'0x80ffbe80d9302a505e2b1ac931f539aed33bf791d1982906ae64c7197324044f191e9bca80972cd2f703f9c94fd516e14b7013c6f1545095855b6c4b36f21d89dad30aa54d80b2495ce4d07001927bb0857611f8d3a1449e791d0b010e3861c32dec0c44179680f5929c8ef9b0ac6ec8a529c91348d8cd6c169920dd37d055544a6c31c53b11e380402a0bf7ff07cee790d9cc065fc138ff6afa7db016d898d65b2b716af354c6f68042aef1dafffd1d9debbb8e6c4eb48b5c141ddf0aad2b0f3f4ddf53e6b38e65c080b31fa0392c1abdce1aa29d1544c94634ecab87ecaba6409db33aaa7621992a8280b1f4de7c3ac5665016d561a60659cd2d8f2d3e0a97e2ea9749279bd8e35eb1f180816ac87a2893694016b21768137a76ea459190ea0fc3c645d85e1a3d4eb194fe802e563b43e7334454c841953424be8c2b7a1c3295dbc391045cb6b88388ad5e7080b1ed3b02e5989b7d134ca056c778f1f5b6ffd377b2d8064483da6e94b82b0e40800cb3299c44a5db8fdcb4932e1b6ab0385d6ef1c9f8d85e0a75b787b6f4fd6c3c805a44c30e2676dc2d4c17451f51d9502e85064387999f366e6f3d404509a7780f80d6788ca71c6aabe421c352027acdb9532563dc5f1b25e6154b721f431e9990ed',
'0x9d0da05ca59913bc38a8630590f2627c154080834dda0ba5adf00d798e981a28a13e728cf83e35aefc87318440a61869f724474c5f0a351b6a99a5b21324516e668bb86a570400505f0e7b9012096b41c4eb3aaf947f6ea4290800007c7700e67da63472835bb0b737093a19ad4c63f5a4efb16ffa83d00700000400',
'0x9e207f03cfdce586301014700e2c25931040505f0e7b9012096b41c4eb3aaf947f6ea4290800004c5f0ec2d17a76153ff51817f12d9cfc3c7f0400',
'0x9e710b30bd2eab0352ddcc26417aa1945fc180699a53b51a9709a3a86039c49b5ef278e9fc244dae27e1a0380c91bff5b0488580c0d4096d94e724b8e86f952e5456c7253776de04c405582d2c350ee172d3eaa77c77081e0bfde17b36573208a06cb5cfba6b63f5a4efb16ffa83d00700000402803d0ae0b8f6832e8fabf0ec62521c2487c58b69eb97060faa8059b00ff6b7262d505f0e7b9012096b41c4eb3aaf947f6ea4290800004c5f03c716fb8fff3de61a883bb76adb34a20400806c8122e0f7f786071d6a51b330d612eccdcbe8d8f79936accabd640506dffdf380a6abfb72ed49b586829cca4ce631c092d45a017ab0d68288d308873025cfe5d280521b868fc212b25f021984cf02ced547cd45952b88360766839dfde7d4683e61',
'0x9ede3d8a54d27e44a9d5ce189618f22d1008505f0e7b9012096b41c4eb3aaf947f6ea42908010080c74756edffa217dfb07ab596d82753deff985ac215e5cc2997d29afe1d397c16',
'0x9ef78c98723ddc9073523ef3beefda0c1004505f0e7b9012096b41c4eb3aaf947f6ea4290800007c77095dac46c07a40d91506e7637ec4ba5763f5a4efb16ffa83d00700000400',
],
},
}

export class InherentProviders implements InherentProvider {
readonly #base: InherentProvider
readonly #providers: CreateInherents[]
Expand Down Expand Up @@ -69,15 +94,23 @@ export class SetValidationData implements CreateInherents {
throw new Error('Parent block not found')
}
const extrinsics = await parentBlock.extrinsics
const method = meta.registry.createType('GenericExtrinsic', extrinsics[this.#expectedIndex])
const validationData = (method as any).args[0].toJSON()

const newData = {
...validationData,
validationData: {
...validationData.validationData,
relayParentNumber: validationData.validationData.relayParentNumber + 2,
},

let newData: typeof MOCK_VALIDATION_DATA

if (parentBlock.number === 0) {
// chain started with genesis, mock 1st validationData
newData = MOCK_VALIDATION_DATA
} else {
const method = meta.registry.createType<GenericExtrinsic>('GenericExtrinsic', extrinsics[this.#expectedIndex])
const validationData = method.args[0].toJSON() as typeof MOCK_VALIDATION_DATA

newData = {
...validationData,
validationData: {
...validationData.validationData,
relayParentNumber: validationData.validationData.relayParentNumber + 2,
},
}
}

const inherent = new GenericExtrinsic(meta.registry, meta.tx.parachainSystem.setValidationData(newData))
Expand Down
Loading