Skip to content

Commit fe59007

Browse files
foriequal0mergify[bot]
authored andcommitted
Disable CustomAction DelegateCCS
However, you can enable it by setting an environment variable `ENABLE_DELEGATIONS=true`, and they are enabled in tests
1 parent 75b4884 commit fe59007

File tree

3 files changed

+263
-3
lines changed

3 files changed

+263
-3
lines changed

core/src/consensus/tendermint/stake/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,37 @@ const CUSTOM_ACTION_HANDLER_ID: u64 = 2;
3838
pub struct Stake {
3939
genesis_stakes: HashMap<Address, u64>,
4040
validators: Arc<ValidatorSet>,
41+
enable_delegations: bool,
4142
}
4243

4344
impl Stake {
45+
#[cfg(not(test))]
4446
pub fn new(genesis_stakes: HashMap<Address, u64>, validators: Arc<ValidatorSet>) -> Stake {
4547
Stake {
4648
genesis_stakes,
4749
validators,
50+
enable_delegations: parse_env_var_enable_delegations(),
4851
}
4952
}
53+
54+
#[cfg(test)]
55+
pub fn new(genesis_stakes: HashMap<Address, u64>, validators: Arc<ValidatorSet>) -> Stake {
56+
Stake {
57+
genesis_stakes,
58+
validators,
59+
enable_delegations: true,
60+
}
61+
}
62+
}
63+
64+
#[cfg(not(test))]
65+
fn parse_env_var_enable_delegations() -> bool {
66+
let var = std::env::var("ENABLE_DELEGATIONS");
67+
match var.as_ref().map(|x| x.trim()) {
68+
Ok(value) => value.parse::<bool>().unwrap(),
69+
Err(std::env::VarError::NotPresent) => false,
70+
Err(err) => unreachable!("{:?}", err),
71+
}
5072
}
5173

5274
impl ActionHandler for Stake {
@@ -79,7 +101,13 @@ impl ActionHandler for Stake {
79101
Action::DelegateCCS {
80102
address,
81103
quantity,
82-
} => delegate_ccs(state, sender, &address, quantity, self.validators.deref()),
104+
} => {
105+
if self.enable_delegations {
106+
delegate_ccs(state, sender, &address, quantity, self.validators.deref())
107+
} else {
108+
Err(RuntimeError::FailedToHandleCustomAction("DelegateCCS is disabled".to_string()).into())
109+
}
110+
}
83111
}
84112
}
85113
}

test/src/e2e.long/staking.test.ts

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,3 +858,228 @@ describe("Staking", function() {
858858
promiseExpect.checkFulfilled();
859859
});
860860
});
861+
862+
describe("Staking-disable-delegation", function() {
863+
this.timeout(60_000);
864+
const promiseExpect = new PromiseExpect();
865+
let nodes: CodeChain[];
866+
867+
beforeEach(async function() {
868+
this.timeout(60_000);
869+
870+
const validatorAddresses = [
871+
validator0Address,
872+
validator1Address,
873+
validator2Address,
874+
validator3Address
875+
];
876+
nodes = validatorAddresses.map(address => {
877+
return new CodeChain({
878+
chain: `${__dirname}/../scheme/tendermint-int.json`,
879+
argv: [
880+
"--engine-signer",
881+
address.toString(),
882+
"--password-path",
883+
"test/tendermint/password.json",
884+
"--force-sealing",
885+
"--no-discovery"
886+
],
887+
additionalKeysPath: "tendermint/keys",
888+
env: {
889+
ENABLE_DELEGATIONS: "false"
890+
}
891+
});
892+
});
893+
await Promise.all(nodes.map(node => node.start()));
894+
});
895+
896+
async function connectEachOther() {
897+
await promiseExpect.shouldFulfill(
898+
"connect",
899+
Promise.all([
900+
nodes[0].connect(nodes[1]),
901+
nodes[0].connect(nodes[2]),
902+
nodes[0].connect(nodes[3]),
903+
nodes[1].connect(nodes[2]),
904+
nodes[1].connect(nodes[3]),
905+
nodes[2].connect(nodes[3])
906+
])
907+
);
908+
await promiseExpect.shouldFulfill(
909+
"wait peers",
910+
Promise.all([
911+
nodes[0].waitPeers(4 - 1),
912+
nodes[1].waitPeers(4 - 1),
913+
nodes[2].waitPeers(4 - 1),
914+
nodes[3].waitPeers(4 - 1)
915+
])
916+
);
917+
}
918+
919+
async function getAllStakingInfo() {
920+
const validatorAddresses = [
921+
faucetAddress,
922+
validator0Address,
923+
validator1Address,
924+
validator2Address,
925+
validator3Address,
926+
aliceAddress,
927+
bobAddress
928+
];
929+
const amounts = await promiseExpect.shouldFulfill(
930+
"get customActionData",
931+
Promise.all(
932+
validatorAddresses.map(addr =>
933+
nodes[0].sdk.rpc.engine.getCustomActionData(
934+
stakeActionHandlerId,
935+
["Account", addr.accountId.toEncodeObject()]
936+
)
937+
)
938+
)
939+
);
940+
const stakeholders = await promiseExpect.shouldFulfill(
941+
"get customActionData",
942+
nodes[0].sdk.rpc.engine.getCustomActionData(stakeActionHandlerId, [
943+
"StakeholderAddresses"
944+
])
945+
);
946+
return { amounts, stakeholders };
947+
}
948+
949+
async function sendStakeToken(params: {
950+
senderAddress: PlatformAddress;
951+
senderSecret: string;
952+
receiverAddress: PlatformAddress;
953+
quantity: number;
954+
fee?: number;
955+
seq?: number;
956+
}): Promise<H256> {
957+
const { fee = 10 } = params;
958+
const seq =
959+
params.seq == null
960+
? await nodes[0].sdk.rpc.chain.getSeq(params.senderAddress)
961+
: params.seq;
962+
963+
return promiseExpect.shouldFulfill(
964+
"sendSignTransaction",
965+
nodes[0].sdk.rpc.chain.sendSignedTransaction(
966+
nodes[0].sdk.core
967+
.createCustomTransaction({
968+
handlerId: stakeActionHandlerId,
969+
bytes: Buffer.from(
970+
RLP.encode([
971+
1,
972+
params.receiverAddress.accountId.toEncodeObject(),
973+
params.quantity
974+
])
975+
)
976+
})
977+
.sign({
978+
secret: params.senderSecret,
979+
seq,
980+
fee
981+
})
982+
)
983+
);
984+
}
985+
986+
async function delegateToken(params: {
987+
senderAddress: PlatformAddress;
988+
senderSecret: string;
989+
receiverAddress: PlatformAddress;
990+
quantity: number;
991+
fee?: number;
992+
seq?: number;
993+
}): Promise<H256> {
994+
const { fee = 10 } = params;
995+
const seq =
996+
params.seq == null
997+
? await nodes[0].sdk.rpc.chain.getSeq(params.senderAddress)
998+
: params.seq;
999+
1000+
return promiseExpect.shouldFulfill(
1001+
"sendSignTransaction",
1002+
nodes[0].sdk.rpc.chain.sendSignedTransaction(
1003+
nodes[0].sdk.core
1004+
.createCustomTransaction({
1005+
handlerId: stakeActionHandlerId,
1006+
bytes: Buffer.from(
1007+
RLP.encode([
1008+
2,
1009+
params.receiverAddress.accountId.toEncodeObject(),
1010+
params.quantity
1011+
])
1012+
)
1013+
})
1014+
.sign({
1015+
secret: params.senderSecret,
1016+
seq,
1017+
fee
1018+
})
1019+
)
1020+
);
1021+
}
1022+
1023+
it("should send stake tokens", async function() {
1024+
await connectEachOther();
1025+
1026+
const hash = await sendStakeToken({
1027+
senderAddress: faucetAddress,
1028+
senderSecret: faucetSecret,
1029+
receiverAddress: validator0Address,
1030+
quantity: 100
1031+
});
1032+
while (!(await nodes[0].sdk.rpc.chain.containsTransaction(hash))) {
1033+
await wait(500);
1034+
}
1035+
1036+
const { amounts, stakeholders } = await getAllStakingInfo();
1037+
expect(amounts).to.be.deep.equal([
1038+
toHex(RLP.encode(70000 - 100)),
1039+
toHex(RLP.encode(100)),
1040+
null,
1041+
null,
1042+
null,
1043+
toHex(RLP.encode(20000)),
1044+
toHex(RLP.encode(10000))
1045+
]);
1046+
expect(stakeholders).to.be.equal(
1047+
toHex(
1048+
RLP.encode(
1049+
[
1050+
faucetAddress.accountId.toEncodeObject(),
1051+
aliceAddress.accountId.toEncodeObject(),
1052+
validator0Address.accountId.toEncodeObject(),
1053+
bobAddress.accountId.toEncodeObject()
1054+
].sort()
1055+
)
1056+
)
1057+
);
1058+
}).timeout(60_000);
1059+
1060+
it("cannot delegate tokens", async function() {
1061+
await connectEachOther();
1062+
const hash = await delegateToken({
1063+
senderAddress: faucetAddress,
1064+
senderSecret: faucetSecret,
1065+
receiverAddress: validator0Address,
1066+
quantity: 100
1067+
});
1068+
const blockNumber = await nodes[0].sdk.rpc.chain.getBestBlockNumber();
1069+
await nodes[0].waitBlockNumber(blockNumber + 1);
1070+
1071+
const err0 = await nodes[0].sdk.rpc.chain.getErrorHint(hash);
1072+
const err1 = await nodes[1].sdk.rpc.chain.getErrorHint(hash);
1073+
const err2 = await nodes[2].sdk.rpc.chain.getErrorHint(hash);
1074+
const err3 = await nodes[3].sdk.rpc.chain.getErrorHint(hash);
1075+
expect(err0 || err1 || err2 || err3).not.null;
1076+
});
1077+
1078+
afterEach(async function() {
1079+
if (this.currentTest!.state === "failed") {
1080+
nodes.map(node => node.testFailed(this.currentTest!.fullTitle()));
1081+
}
1082+
await Promise.all(nodes.map(node => node.clean()));
1083+
promiseExpect.checkFulfilled();
1084+
});
1085+
});

test/src/helper/spawn.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default class CodeChain {
6565
private readonly _chain: ChainType;
6666
private readonly _rpcPort: number;
6767
private readonly argv: string[];
68+
private readonly env: { [key: string]: string };
6869
private isTestFailed: boolean;
6970
private process?: ChildProcess;
7071
private readonly keyFileMovePromise?: Promise<{}>;
@@ -112,9 +113,10 @@ export default class CodeChain {
112113
argv?: string[];
113114
additionalKeysPath?: string;
114115
rpcPort?: number;
116+
env?: { [key: string]: string };
115117
} = {}
116118
) {
117-
const { chain, argv, additionalKeysPath } = options;
119+
const { chain, argv, additionalKeysPath, env } = options;
118120
this._id = CodeChain.idCounter++;
119121

120122
const { rpcPort = 8081 + this.id } = options;
@@ -148,6 +150,7 @@ export default class CodeChain {
148150
this._sdk = new SDK({ server: `http://localhost:${this.rpcPort}` });
149151
this._chain = chain || "solo";
150152
this.argv = argv || [];
153+
this.env = env || {};
151154
this.isTestFailed = false;
152155
}
153156

@@ -201,7 +204,11 @@ export default class CodeChain {
201204
],
202205
{
203206
cwd: projectRoot,
204-
env: process.env
207+
env: {
208+
...process.env,
209+
ENABLE_DELEGATIONS: "true",
210+
...this.env
211+
}
205212
}
206213
);
207214

0 commit comments

Comments
 (0)