Skip to content

Commit 6c83874

Browse files
committed
Implement rpc chain_getTermMetadata
1 parent 5f9cea0 commit 6c83874

File tree

5 files changed

+190
-2
lines changed

5 files changed

+190
-2
lines changed

core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub use crate::block::Block;
8484
pub use crate::client::Error::Database;
8585
pub use crate::client::{
8686
AccountData, AssetClient, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient,
87-
EngineClient, EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, Shard, StateInfo,
87+
EngineClient, EngineInfo, ExecuteClient, ImportBlock, MetadataInfo, MiningBlockChainClient, Shard, StateInfo,
8888
TestBlockChainClient, TextClient,
8989
};
9090
pub use crate::consensus::{EngineType, TimeGapParams};

rpc/src/v1/impls/chain.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
use std::convert::{TryFrom, TryInto};
1818
use std::sync::Arc;
1919

20-
use ccore::{AccountData, AssetClient, BlockId, EngineInfo, ExecuteClient, MiningBlockChainClient, Shard, TextClient};
20+
use ccore::{
21+
AccountData, AssetClient, BlockId, EngineInfo, ExecuteClient, MetadataInfo, MiningBlockChainClient, Shard,
22+
TextClient,
23+
};
2124
use ccrypto::Blake;
2225
use cjson::scheme::Params;
2326
use cjson::uint::Uint;
@@ -60,6 +63,7 @@ where
6063
+ EngineInfo
6164
+ FindActionHandler
6265
+ TextClient
66+
+ MetadataInfo
6367
+ 'static,
6468
{
6569
fn get_transaction(&self, transaction_hash: H256) -> Result<Option<Transaction>> {
@@ -300,6 +304,11 @@ where
300304
Ok(self.client.common_params(block_id).map(Into::<Params>::into))
301305
}
302306

307+
fn get_term_metadata(&self, block_number: Option<u64>) -> Result<Option<(u64, u64)>> {
308+
let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest);
309+
Ok(self.client.metadata(block_id).map(|m| (m.last_term_finished_block_num(), m.current_term_id())))
310+
}
311+
303312
fn execute_transaction(&self, tx: UnsignedTransaction, sender: PlatformAddress) -> Result<Option<String>> {
304313
let sender_address = sender.try_address().map_err(errors::core)?;
305314
let action = Action::try_from(tx.action).map_err(errors::conversion)?;

rpc/src/v1/traits/chain.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

17+
use cjson::scheme::Params;
1718
use cjson::uint::Uint;
1819
use ckey::{NetworkId, PlatformAddress, Public};
1920
use ctypes::{BlockNumber, ShardId};
@@ -140,6 +141,10 @@ build_rpc_trait! {
140141
#[rpc(name = "chain_getCommonParams")]
141142
fn get_common_params(&self, Option<u64>) -> Result<Option<Params>>;
142143

144+
/// Return the current term id at given block number
145+
#[rpc(name = "chain_getTermMetadata")]
146+
fn get_term_metadata(&self, Option<u64>) -> Result<Option<(u64, u64)>>;
147+
143148
/// Execute Transactions
144149
# [rpc(name = "chain_executeTransaction")]
145150
fn execute_transaction(&self, UnsignedTransaction, PlatformAddress) -> Result<Option<String>>;

state/src/item/metadata.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ impl Metadata {
102102
pub fn last_term_finished_block_num(&self) -> u64 {
103103
self.term.last_term_finished_block_num
104104
}
105+
106+
pub fn current_term_id(&self) -> u64 {
107+
self.term.current_term_id
108+
}
105109
}
106110

107111
impl Default for Metadata {

test/src/e2e/termChange.test.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright 2019 Kodebox, Inc.
2+
// This file is part of CodeChain.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as
6+
// published by the Free Software Foundation, either version 3 of the
7+
// License, or (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
import { expect } from "chai";
18+
import { blake256 } from "codechain-sdk/lib/utils";
19+
import "mocha";
20+
import {
21+
aliceAddress,
22+
aliceSecret,
23+
carolSecret,
24+
faucetAddress,
25+
faucetSecret,
26+
stakeActionHandlerId,
27+
validator0Address
28+
} from "../helper/constants";
29+
import CodeChain from "../helper/spawn";
30+
31+
const RLP = require("rlp");
32+
33+
describe("ChangeParams", function() {
34+
const chain = `${__dirname}/../scheme/solo-block-reward-50.json`;
35+
let node: CodeChain;
36+
37+
beforeEach(async function() {
38+
node = new CodeChain({
39+
chain,
40+
argv: ["--author", validator0Address.toString(), "--force-sealing"]
41+
});
42+
await node.start();
43+
44+
const tx = await node.sendPayTx({
45+
fee: 10,
46+
quantity: 100_000,
47+
recipient: aliceAddress
48+
});
49+
expect(await node.sdk.rpc.chain.containsTransaction(tx.hash())).be.true;
50+
});
51+
52+
async function changeTermSeconds(metadataSeq: number, termSeconds: number) {
53+
const newParams = [
54+
0x20, // maxExtraDataSize
55+
0x0400, // maxAssetSchemeMetadataSize
56+
0x0100, // maxTransferMetadataSize
57+
0x0200, // maxTextContentSize
58+
"tc", // networkID
59+
10, // minPayCost
60+
10, // minSetRegularKeyCost
61+
10, // minCreateShardCost
62+
10, // minSetShardOwnersCost
63+
10, // minSetShardUsersCost
64+
10, // minWrapCccCost
65+
10, // minCustomCost
66+
10, // minStoreCost
67+
10, // minRemoveCost
68+
10, // minMintAssetCost
69+
10, // minTransferAssetCost
70+
10, // minChangeAssetSchemeCost
71+
10, // minIncreaseAssetSupplyCost
72+
10, // minComposeAssetCost
73+
10, // minDecomposeAssetCost
74+
10, // minUnwrapCccCost
75+
4194304, // maxBodySize
76+
16384, // snapshotPeriod
77+
termSeconds, // termSeconds
78+
0, // nominationExpiration
79+
0, // custodyPeriod
80+
0, // releasePeriod
81+
0, // maxNumOfValidators
82+
0, // minNumOfValidators
83+
0, // delegationThreshold
84+
0 // minDeposit
85+
];
86+
const changeParams: (number | string | (number | string)[])[] = [
87+
0xff,
88+
metadataSeq,
89+
newParams
90+
];
91+
const message = blake256(RLP.encode(changeParams).toString("hex"));
92+
changeParams.push(`0x${node.sdk.util.signEcdsa(message, aliceSecret)}`);
93+
changeParams.push(`0x${node.sdk.util.signEcdsa(message, carolSecret)}`);
94+
95+
{
96+
const hash = await node.sdk.rpc.chain.sendSignedTransaction(
97+
node.sdk.core
98+
.createCustomTransaction({
99+
handlerId: stakeActionHandlerId,
100+
bytes: RLP.encode(changeParams)
101+
})
102+
.sign({
103+
secret: faucetSecret,
104+
seq: await node.sdk.rpc.chain.getSeq(faucetAddress),
105+
fee: 10
106+
})
107+
);
108+
expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true;
109+
}
110+
}
111+
112+
it("initial term metadata", async function() {
113+
const params = await node.sdk.rpc.sendRpcRequest(
114+
"chain_getTermMetadata",
115+
[null]
116+
);
117+
expect(params).to.be.deep.equals([0, 0]);
118+
});
119+
120+
async function waitForTermPeriodChange(termSeconds: number) {
121+
const lastBlockNumber = await node.sdk.rpc.chain.getBestBlockNumber();
122+
const lastBlock = (await node.sdk.rpc.chain.getBlock(lastBlockNumber))!;
123+
124+
let previousTs = lastBlock.timestamp;
125+
for (let count = 0; count < 20; count++) {
126+
await node.sdk.rpc.devel.startSealing();
127+
const blockNumber = await node.sdk.rpc.chain.getBestBlockNumber();
128+
const block = (await node.sdk.rpc.chain.getBlock(blockNumber))!;
129+
130+
const currentTs = block.timestamp;
131+
const previousTermPeriod = Math.floor(previousTs / termSeconds);
132+
const currentTermPeriod = Math.floor(currentTs / termSeconds);
133+
if (previousTermPeriod !== currentTermPeriod) {
134+
return blockNumber;
135+
}
136+
previousTs = currentTs;
137+
await new Promise(resolve => setTimeout(resolve, 1000));
138+
}
139+
140+
throw new Error("Timeout on waiting term period change");
141+
}
142+
143+
it("can turn on term change", async function() {
144+
const TERM_SECONDS = 3;
145+
await changeTermSeconds(0, TERM_SECONDS);
146+
147+
const blockNumber1 = await waitForTermPeriodChange(TERM_SECONDS);
148+
149+
const params1 = await node.sdk.rpc.sendRpcRequest(
150+
"chain_getTermMetadata",
151+
[blockNumber1]
152+
);
153+
expect(params1).to.be.deep.equals([blockNumber1, 1]);
154+
155+
const blockNumber2 = await waitForTermPeriodChange(TERM_SECONDS);
156+
157+
const params2 = await node.sdk.rpc.sendRpcRequest(
158+
"chain_getTermMetadata",
159+
[blockNumber2]
160+
);
161+
expect(params2).to.be.deep.equals([blockNumber2, 2]);
162+
});
163+
164+
afterEach(async function() {
165+
if (this.currentTest!.state === "failed") {
166+
node.testFailed(this.currentTest!.fullTitle());
167+
}
168+
await node.clean();
169+
});
170+
});

0 commit comments

Comments
 (0)