Skip to content

Commit

Permalink
[harmony] updated data structures and tests for harmony staking suppo…
Browse files Browse the repository at this point in the history
…rt (trustwallet#894)

* added extra field for harmony staking
* updated harmony staking fields
  • Loading branch information
coolcottontail authored Mar 19, 2020
1 parent 83079c4 commit ee15d8b
Show file tree
Hide file tree
Showing 7 changed files with 439 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class TestHarmonyStakingDelegateSigner {
val oneAddress = "one1a0x3d6xpmr6f8wsyaxd9v36pytvp48zckswvv9"
val privateKeyData = ByteString.copyFrom(PrivateKey("4edef2c24995d15b0e25cbd152fb0e2c05d3b79b9c2afd134e6f59f91bf99e48".toHexByteArray()).data())
val pubKeyData = ByteString.copyFrom("b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611".toHexByteArray())
val blsSigData = ByteString.copyFrom("4252b0f1210efb0d5061e8a706a7ea9d62292a7947a975472fb77e1af7278a1c3c2e6eeba73c0581ece398613829940df129f3071c9a24b4b448bb1e880dc5872a58cb07eed94294c4e01a5c864771cafef7b96be541cb3c521a98f01838dd94".toHexByteArray())

init {
System.loadLibrary("TrustWalletCore")
Expand Down Expand Up @@ -52,6 +53,7 @@ class TestHarmonyStakingDelegateSigner {
maxChangeRate = mcr.build()
}
val pubKey = pubKeyData
val blsSig = blsSigData
val createValidator = Harmony.DirectiveCreateValidator.newBuilder()
createValidator.apply {
validatorAddress = oneAddress
Expand All @@ -60,6 +62,7 @@ class TestHarmonyStakingDelegateSigner {
minSelfDelegation = ByteString.copyFrom("0xa".toHexByteArray())
maxTotalDelegation = ByteString.copyFrom("0x0bb8".toHexByteArray())
addAllSlotPubKeys(listOf(pubKey))
addAllSlotKeySigs(listOf(blsSig))
amount = ByteString.copyFrom("0x64".toHexByteArray())
}
return createValidator
Expand All @@ -83,12 +86,12 @@ class TestHarmonyStakingDelegateSigner {
}
val sign = AnySigner.sign(signingInput.build(), HARMONY, SigningOutput.parser())

val expected = "0xf8ed80f8a494ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121ddc988016345785d8a0000c9880c7d713b49da0000c887b1a2bc2ec500000a820bb8f1b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b622476086116402806428a0476e8a0fe478e0d03ff10222d4d590bca8cee3ec51b830f4fc4a8bee5d0e9d28a03b2be18e73b2f99d7e2691485a0e166f28e62815079c126e68f876dc97339f8f"
val expected = "0xf9015280f9010894ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121ddc988016345785d8a0000c9880c7d713b49da0000c887b1a2bc2ec500000a820bb8f1b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611f862b8604252b0f1210efb0d5061e8a706a7ea9d62292a7947a975472fb77e1af7278a1c3c2e6eeba73c0581ece398613829940df129f3071c9a24b4b448bb1e880dc5872a58cb07eed94294c4e01a5c864771cafef7b96be541cb3c521a98f01838dd946402806428a00d8437f81be3481b01542e9baef0445f3758cf084c5e1fba93d087ccce084cb1a0404c1a42442c2d39f84582353a1c67012451ff83ef6d3622f684041df9bf0072"

assertEquals(Numeric.toHexString(sign.encoded.toByteArray()), expected)
assertEquals(Numeric.toHexString(sign.v.toByteArray()), "0x28")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x476e8a0fe478e0d03ff10222d4d590bca8cee3ec51b830f4fc4a8bee5d0e9d28")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x3b2be18e73b2f99d7e2691485a0e166f28e62815079c126e68f876dc97339f8f")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x0d8437f81be3481b01542e9baef0445f3758cf084c5e1fba93d087ccce084cb1")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x404c1a42442c2d39f84582353a1c67012451ff83ef6d3622f684041df9bf0072")
}

@Test
Expand All @@ -115,6 +118,8 @@ class TestHarmonyStakingDelegateSigner {
maxTotalDelegation = ByteString.copyFrom("0x0bb8".toHexByteArray())
slotKeyToRemove = pubKeyData
slotKeyToAdd = pubKeyData
slotKeyToAddSig = blsSigData
active = ByteString.copyFrom("0x1".toHexByteArray())
}
val staking = Harmony.StakingMessage.newBuilder()
staking.apply {
Expand All @@ -131,12 +136,112 @@ class TestHarmonyStakingDelegateSigner {
}

val sign = AnySigner.sign(signingInput.build(), HARMONY, SigningOutput.parser())
val expected = "0xf9010801f8bf94ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c988016345785d8a00000a820bb8b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b6224760861102806427a05e54b55272f6bf5ffeca10d85976749d6b844cc9f30ba3285b9ab8a82d53e3e3a03ce04d9a9f834e20b22aa918ead346c84a04b1504fe3ff9e38f21c5e5712f013"
val expected = "0xf9016c01f9012294ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c988016345785d8a00000a820bb8b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b8604252b0f1210efb0d5061e8a706a7ea9d62292a7947a975472fb77e1af7278a1c3c2e6eeba73c0581ece398613829940df129f3071c9a24b4b448bb1e880dc5872a58cb07eed94294c4e01a5c864771cafef7b96be541cb3c521a98f01838dd940102806427a089d6f87855619c31e933d5f00638ca58737dfffdfdf8b66a048a2e45f103e05da04aafc5c51a95412760c089371b411a5ab8f235b456291a9754d544b162df4eef"

assertEquals(Numeric.toHexString(sign.encoded.toByteArray()), expected)
assertEquals(Numeric.toHexString(sign.v.toByteArray()), "0x27")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x5e54b55272f6bf5ffeca10d85976749d6b844cc9f30ba3285b9ab8a82d53e3e3")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x3ce04d9a9f834e20b22aa918ead346c84a04b1504fe3ff9e38f21c5e5712f013")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x89d6f87855619c31e933d5f00638ca58737dfffdfdf8b66a048a2e45f103e05d")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x4aafc5c51a95412760c089371b411a5ab8f235b456291a9754d544b162df4eef")
}

@Test
fun testHarmonyStakingTransactionEditValidatorSigning2() {
val desc = Harmony.Description.newBuilder()
desc.apply {
name = "Alice"
identity = "alice"
website = "alice.harmony.one"
securityContact = "Bob"
details = "Don't mess with me!!!"
}
val rate = Harmony.Decimal.newBuilder()
rate.apply {
value = ByteString.copyFrom("0x1".toHexByteArray())
precision = ByteString.copyFrom("0x1".toHexByteArray())
}
val editValidator = Harmony.DirectiveEditValidator.newBuilder()
editValidator.apply {
validatorAddress = oneAddress
description = desc.build()
commissionRate = rate.build()
minSelfDelegation = ByteString.copyFrom("0xa".toHexByteArray())
maxTotalDelegation = ByteString.copyFrom("0x0bb8".toHexByteArray())
slotKeyToRemove = pubKeyData
slotKeyToAdd = pubKeyData
slotKeyToAddSig = blsSigData
active = ByteString.copyFrom("0x2".toHexByteArray())
}
val staking = Harmony.StakingMessage.newBuilder()
staking.apply {
nonce = ByteString.copyFrom("0x2".toHexByteArray())
gasPrice = ByteString.copyFrom("0x0".toHexByteArray())
gasLimit = ByteString.copyFrom("0x64".toHexByteArray())
editValidatorMessage = editValidator.build()
}
val signingInput = Harmony.SigningInput.newBuilder()
signingInput.apply {
privateKey = privateKeyData
chainId = ByteString.copyFrom("0x02".toHexByteArray())
stakingMessage = staking.build()
}

val sign = AnySigner.sign(signingInput.build(), HARMONY, SigningOutput.parser())
val expected = "0xf9016c01f9012294ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c988016345785d8a00000a820bb8b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b8604252b0f1210efb0d5061e8a706a7ea9d62292a7947a975472fb77e1af7278a1c3c2e6eeba73c0581ece398613829940df129f3071c9a24b4b448bb1e880dc5872a58cb07eed94294c4e01a5c864771cafef7b96be541cb3c521a98f01838dd940202806428a09d1212ab7f54b05a4f89506ea1fe3bebecf5126544bc990b53b27f1fccb69d52a01d13704dce7399f154c2352d61ad1fc208880c267695cb423c57cd52b9821a79"

assertEquals(Numeric.toHexString(sign.encoded.toByteArray()), expected)
assertEquals(Numeric.toHexString(sign.v.toByteArray()), "0x28")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x9d1212ab7f54b05a4f89506ea1fe3bebecf5126544bc990b53b27f1fccb69d52")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x1d13704dce7399f154c2352d61ad1fc208880c267695cb423c57cd52b9821a79")
}

@Test
fun testHarmonyStakingTransactionEditValidatorSigning3() {
val desc = Harmony.Description.newBuilder()
desc.apply {
name = "Alice"
identity = "alice"
website = "alice.harmony.one"
securityContact = "Bob"
details = "Don't mess with me!!!"
}
val rate = Harmony.Decimal.newBuilder()
rate.apply {
value = ByteString.copyFrom("0x1".toHexByteArray())
precision = ByteString.copyFrom("0x1".toHexByteArray())
}
val editValidator = Harmony.DirectiveEditValidator.newBuilder()
editValidator.apply {
validatorAddress = oneAddress
description = desc.build()
commissionRate = rate.build()
minSelfDelegation = ByteString.copyFrom("0xa".toHexByteArray())
maxTotalDelegation = ByteString.copyFrom("0x0bb8".toHexByteArray())
slotKeyToRemove = pubKeyData
slotKeyToAdd = pubKeyData
slotKeyToAddSig = blsSigData
active = ByteString.copyFrom("0x0".toHexByteArray())
}
val staking = Harmony.StakingMessage.newBuilder()
staking.apply {
nonce = ByteString.copyFrom("0x2".toHexByteArray())
gasPrice = ByteString.copyFrom("0x0".toHexByteArray())
gasLimit = ByteString.copyFrom("0x64".toHexByteArray())
editValidatorMessage = editValidator.build()
}
val signingInput = Harmony.SigningInput.newBuilder()
signingInput.apply {
privateKey = privateKeyData
chainId = ByteString.copyFrom("0x02".toHexByteArray())
stakingMessage = staking.build()
}

val sign = AnySigner.sign(signingInput.build(), HARMONY, SigningOutput.parser())
val expected = "0xf9016c01f9012294ebcd16e8c1d8f493ba04e99a56474122d81a9c58f83885416c69636585616c69636591616c6963652e6861726d6f6e792e6f6e6583426f6295446f6e2774206d6573732077697468206d65212121c988016345785d8a00000a820bb8b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b0b9486167ab9087ab818dc4ce026edb5bf216863364c32e42df2af03c5ced1ad181e7d12f0e6dd5307a73b62247608611b8604252b0f1210efb0d5061e8a706a7ea9d62292a7947a975472fb77e1af7278a1c3c2e6eeba73c0581ece398613829940df129f3071c9a24b4b448bb1e880dc5872a58cb07eed94294c4e01a5c864771cafef7b96be541cb3c521a98f01838dd948002806427a02f160fbf125b614764f9d45dc20acc63da41b02f380e20135e72bc7e74ab3205a011a1d8824a871361e2817145e87148b072c378c38d037df482214a3e4e3f2205"

assertEquals(Numeric.toHexString(sign.encoded.toByteArray()), expected)
assertEquals(Numeric.toHexString(sign.v.toByteArray()), "0x27")
assertEquals(Numeric.toHexString(sign.r.toByteArray()), "0x2f160fbf125b614764f9d45dc20acc63da41b02f380e20135e72bc7e74ab3205")
assertEquals(Numeric.toHexString(sign.s.toByteArray()), "0x11a1d8824a871361e2817145e87148b072c378c38d037df482214a3e4e3f2205")
}

@Test
Expand Down
24 changes: 22 additions & 2 deletions src/Harmony/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "../Ethereum/RLP.h"
#include "../HexCoding.h"


using namespace TW;
using namespace TW::Harmony;

Expand Down Expand Up @@ -142,6 +143,10 @@ Proto::SigningOutput Signer::signCreateValidator(const Proto::SigningInput &inpu
for (auto pk : input.staking_message().create_validator_message().slot_pub_keys()) {
slotPubKeys.push_back(Data(pk.begin(), pk.end()));
}
std::vector<Data> slotKeySigs;
for (auto sig : input.staking_message().create_validator_message().slot_key_sigs()) {
slotKeySigs.push_back(Data(sig.begin(), sig.end()));
}
Address validatorAddr;
if (!Address::decode(input.staking_message().create_validator_message().validator_address(),
validatorAddr)) {
Expand All @@ -157,6 +162,7 @@ Proto::SigningOutput Signer::signCreateValidator(const Proto::SigningInput &inpu
/* MaxTotalDelegation */
load(input.staking_message().create_validator_message().max_total_delegation()),
/* PubKey */ slotPubKeys,
/* BlsSig */ slotKeySigs,
/* Amount */ load(input.staking_message().create_validator_message().amount()));

auto stakingTx = Staking<CreateValidator>(
Expand Down Expand Up @@ -210,9 +216,14 @@ Proto::SigningOutput Signer::signEditValidator(const Proto::SigningInput &input)
/* SlotKeyToRemove */
Data(input.staking_message().edit_validator_message().slot_key_to_remove().begin(),
input.staking_message().edit_validator_message().slot_key_to_remove().end()),
/* SlotKeyToRemove */
/* SlotKeyToAdd */
Data(input.staking_message().edit_validator_message().slot_key_to_add().begin(),
input.staking_message().edit_validator_message().slot_key_to_add().end()));
input.staking_message().edit_validator_message().slot_key_to_add().end()),
/* SlotKeyToAddSig */
Data(input.staking_message().edit_validator_message().slot_key_to_add_sig().begin(),
input.staking_message().edit_validator_message().slot_key_to_add_sig().end()),
/* Active */
load(input.staking_message().edit_validator_message().active()));

auto stakingTx = Staking<EditValidator>(
DirectiveEditValidator, editValidator, load(input.staking_message().nonce()),
Expand Down Expand Up @@ -404,6 +415,12 @@ Data Signer::rlpNoHashDirective(const Staking<CreateValidator> &transaction) con
}
append(encoded, RLP::encodeList(slotPubKeysEncoded));

auto slotBlsSigsEncoded = Data();
for (auto sig : transaction.stakeMsg.slotKeySigs) {
append(slotBlsSigsEncoded, RLP::encode(sig));
}
append(encoded, RLP::encodeList(slotBlsSigsEncoded));

append(encoded, RLP::encode(transaction.stakeMsg.amount));

return RLP::encodeList(encoded);
Expand Down Expand Up @@ -434,6 +451,9 @@ Data Signer::rlpNoHashDirective(const Staking<EditValidator> &transaction) const

append(encoded, RLP::encode(transaction.stakeMsg.slotKeyToRemove));
append(encoded, RLP::encode(transaction.stakeMsg.slotKeyToAdd));
append(encoded, RLP::encode(transaction.stakeMsg.slotKeyToAddSig));

append(encoded, RLP::encode(transaction.stakeMsg.active));

return RLP::encodeList(encoded);
}
Expand Down
15 changes: 11 additions & 4 deletions src/Harmony/Staking.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,20 @@ class CreateValidator {
uint256_t maxTotalDelegation;
uint256_t amount;
vector<vector<uint8_t>> slotPubKeys;
vector<vector<uint8_t>> slotKeySigs;

CreateValidator(Address validatorAddress, Description description,
CommissionRate commissionRates, uint256_t minSelfDelegation,
uint256_t maxTotalDelegation, vector<vector<uint8_t>> slotPubKeys,
uint256_t amount)
vector<vector<uint8_t>> slotKeySigs,uint256_t amount)
: validatorAddress(move(validatorAddress))
, description(move(description))
, commissionRates(move(commissionRates))
, minSelfDelegation(move(minSelfDelegation))
, maxTotalDelegation(move(maxTotalDelegation))
, amount(move(amount))
, slotPubKeys(move(slotPubKeys)) {}
, slotPubKeys(move(slotPubKeys))
, slotKeySigs(move(slotKeySigs)) {}
};

class EditValidator {
Expand All @@ -129,17 +131,22 @@ class EditValidator {
uint256_t maxTotalDelegation;
vector<uint8_t> slotKeyToRemove;
vector<uint8_t> slotKeyToAdd;
vector<uint8_t> slotKeyToAddSig;
uint256_t active;

EditValidator(Address validatorAddress, Description description, Decimal *commissionRate,
uint256_t minSelfDelegation, uint256_t maxTotalDelegation,
vector<uint8_t> slotKeyToRemove, vector<uint8_t> slotKeyToAdd)
vector<uint8_t> slotKeyToRemove, vector<uint8_t> slotKeyToAdd,
vector<uint8_t> slotKeyToAddSig, uint256_t active)
: validatorAddress(move(validatorAddress))
, description(move(description))
, commissionRate(move(commissionRate))
, minSelfDelegation(move(minSelfDelegation))
, maxTotalDelegation(move(maxTotalDelegation))
, slotKeyToRemove(move(slotKeyToRemove))
, slotKeyToAdd(move(slotKeyToAdd)) {}
, slotKeyToAdd(move(slotKeyToAdd))
, slotKeyToAddSig(move(slotKeyToAddSig))
, active(move(active)){}
};

class Delegate {
Expand Down
5 changes: 4 additions & 1 deletion src/proto/Harmony.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ message DirectiveCreateValidator {
bytes min_self_delegation = 4;
bytes max_total_delegation = 5;
repeated bytes slot_pub_keys = 6;
bytes amount = 7;
repeated bytes slot_key_sigs = 7;
bytes amount = 8;
}

message DirectiveEditValidator {
Expand All @@ -110,6 +111,8 @@ message DirectiveEditValidator {
bytes max_total_delegation = 5;
bytes slot_key_to_remove = 6;
bytes slot_key_to_add = 7;
bytes slot_key_to_add_sig = 8;
bytes active = 9;
}

message DirectiveDelegate {
Expand Down
Loading

0 comments on commit ee15d8b

Please sign in to comment.