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

feat: add transaction_v1 group of functions #819

Merged
merged 4 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 3 additions & 1 deletion packages/core/src/rpc/rpc-spec/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as ChainHeadV1RPC from './chainHead_v1.js'
import * as TransactionV1RPC from './transaction_v1.js'

export { ChainHeadV1RPC }
export { ChainHeadV1RPC, TransactionV1RPC }

const handlers = {
...ChainHeadV1RPC,
...TransactionV1RPC,
}

export default handlers
33 changes: 33 additions & 0 deletions packages/core/src/rpc/rpc-spec/transaction_v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Handler } from '../shared.js'
import { HexString } from '@polkadot/util/types'
import { defaultLogger } from '../../logger.js'

const logger = defaultLogger.child({ name: 'rpc-transaction_v1' })
const randomId = () => Math.random().toString(36).substring(2)

/**
* Submit the extrinsic to the transaction pool
*
* @param context
* @param params - [`extrinsic`]
*
* @return operation id
*/
export const transaction_v1_broadcast: Handler<[HexString], string | null> = async (context, [extrinsic]) => {
await context.chain.submitExtrinsic(extrinsic).catch((err) => {
// As per the spec, the invalid transaction errors should be ignored.
logger.warn('Submit extrinsic failed', err)
})

return randomId()
ermalkaleci marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Stop broadcasting the transaction to other nodes.
*
*/
export const transaction_v1_stop: Handler<[string], null> = async (_context, [_operationId]) => {
// Chopsticks doesn't have any process to broadcast the transaction through P2P
// so stopping doesn't have any effect.
return null
}
3 changes: 2 additions & 1 deletion packages/e2e/src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export const setupPolkadotApi = async (option: SetupOption) => {
chain: null as unknown as Blockchain,
substrateClient: null as unknown as SubstrateClient,
observableClient: null as unknown as ObservableClient,
ws: null as unknown as WsProvider,
}

beforeAll(async () => {
Expand All @@ -212,7 +213,7 @@ export const setupPolkadotApi = async (option: SetupOption) => {

beforeEach(async () => {
const res = await setup()
ws = res.ws
ws = result.ws = res.ws
chain = result.chain = res.chain
result.substrateClient = res.substrateClient
result.observableClient = res.observableClient
Expand Down
65 changes: 65 additions & 0 deletions packages/e2e/src/rpc-spec.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ApiPromise } from '@polkadot/api'
import { describe, expect, it } from 'vitest'
import { dev, env, observe, setupPolkadotApi, testingPairs } from './helper.js'

const testApi = await setupPolkadotApi(env.acalaV15)

const { alice, bob } = testingPairs()

describe('transaction_v1', async () => {
it('sends and executes transactions', async () => {
const chainHead = testApi.observableClient.chainHead$()

const api = await prepareChainForTx()

const tx = await api.tx.balances.transferKeepAlive(bob.address, 100n).signAsync(alice)
const { nextValue, subscription } = observe(chainHead.trackTx$(tx.toHex()))
const resultPromise = nextValue()
const broadcast = testApi.observableClient.broadcastTx$(tx.toHex()).subscribe()

// We don't have a confirmation of when the transaction has been broadcasted through the network
// it just continues to get broadcasted through the nodes until we unsubscribe from it.
// In this case, where there's only one node, waiting for 300ms should be enough.
await new Promise((resolve) => setTimeout(resolve, 300))
const hash = await dev.newBlock()
ermalkaleci marked this conversation as resolved.
Show resolved Hide resolved

expect(await resultPromise).toMatchObject({
hash,
found: {
type: true,
},
})

broadcast.unsubscribe()
subscription.unsubscribe()
chainHead.unfollow()
})
})

const UPGRADED = 0x80000000_00000000_00000000_00000000n
const INITIAL_ACCOUNT_VALUE = 100_000_000_000_000n
async function prepareChainForTx() {
const api = await ApiPromise.create({
ermalkaleci marked this conversation as resolved.
Show resolved Hide resolved
provider: testApi.ws,
noInitWarn: true,
})
await api.isReady
await dev.setStorage({
System: {
Account: [
[
[alice.address],
{
data: { free: INITIAL_ACCOUNT_VALUE, flags: UPGRADED },
ermalkaleci marked this conversation as resolved.
Show resolved Hide resolved
},
],
[[bob.address], { data: { free: INITIAL_ACCOUNT_VALUE, flags: UPGRADED } }],
],
},
Sudo: {
Key: alice.address,
},
})

return api
}
Loading