Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14864819
D6914.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Subscribers
None
D6914.diff
View Options
diff --git a/src/avalanche/proof.h b/src/avalanche/proof.h
--- a/src/avalanche/proof.h
+++ b/src/avalanche/proof.h
@@ -117,6 +117,7 @@
uint64_t getSequence() const { return sequence; }
int64_t getExpirationTime() const { return expirationTime; }
const CPubKey &getMaster() const { return master; }
+ const std::vector<SignedStake> &getStakes() const { return stakes; }
const ProofId &getId() const { return proofid; }
uint32_t getScore() const;
diff --git a/src/rpc/avalanche.cpp b/src/rpc/avalanche.cpp
--- a/src/rpc/avalanche.cpp
+++ b/src/rpc/avalanche.cpp
@@ -4,6 +4,7 @@
#include <avalanche/processor.h>
#include <avalanche/proof.h>
+#include <avalanche/proofbuilder.h>
#include <config.h>
#include <key_io.h>
#include <rpc/server.h>
@@ -30,6 +31,18 @@
return HexStr(g_avalanche->getSessionPubKey());
}
+static CPubKey ParsePubKey(const UniValue ¶m) {
+ const std::string keyHex = param.get_str();
+ if ((keyHex.length() != 2 * CPubKey::COMPRESSED_PUBLIC_KEY_SIZE &&
+ keyHex.length() != 2 * CPubKey::PUBLIC_KEY_SIZE) ||
+ !IsHex(keyHex)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
+ strprintf("Invalid public key: %s\n", keyHex));
+ }
+
+ return HexToPubKey(keyHex);
+}
+
static UniValue addavalanchenode(const Config &config,
const JSONRPCRequest &request) {
RPCHelpMan{
@@ -58,22 +71,129 @@
}
const NodeId nodeid = request.params[0].get_int64();
-
- // Parse the pubkey
- const std::string keyHex = request.params[1].get_str();
- if ((keyHex.length() != 2 * CPubKey::COMPRESSED_PUBLIC_KEY_SIZE &&
- keyHex.length() != 2 * CPubKey::PUBLIC_KEY_SIZE) ||
- !IsHex(keyHex)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
- strprintf("Invalid public key: %s\n", keyHex));
- }
+ const CPubKey key = ParsePubKey(request.params[1]);
CDataStream ss(ParseHexV(request.params[2], "proof"), SER_NETWORK,
PROTOCOL_VERSION);
avalanche::Proof proof;
ss >> proof;
- return g_avalanche->addNode(nodeid, proof, {HexToPubKey(keyHex)});
+ return g_avalanche->addNode(nodeid, proof, key);
+}
+
+static UniValue buildavalancheproof(const Config &config,
+ const JSONRPCRequest &request) {
+ RPCHelpMan{
+ "buildavalancheproof",
+ "\nBuild a proof for avalanche's sybil resistance.\n",
+ {
+ {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO,
+ "The proof's sequence"},
+ {"expiration", RPCArg::Type::NUM, RPCArg::Optional::NO,
+ "A timestamp indicating when the proof expire"},
+ {"master", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
+ "The master public key"},
+ {
+ "stakes",
+ RPCArg::Type::ARR,
+ RPCArg::Optional::NO,
+ "The stakes to be signed and associated private keys",
+ {
+ {
+ "stake",
+ RPCArg::Type::OBJ,
+ RPCArg::Optional::NO,
+ "A stake to be attached to this proof",
+ {
+ {"txid", RPCArg::Type::STR_HEX,
+ RPCArg::Optional::NO, "The transaction id"},
+ {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO,
+ "The output number"},
+ {"amount", RPCArg::Type::AMOUNT,
+ RPCArg::Optional::NO, "The amount in this UTXO"},
+ {"height", RPCArg::Type::NUM, RPCArg::Optional::NO,
+ "The height at which this UTXO was mined"},
+ {"iscoinbase", RPCArg::Type::BOOL,
+ /* default */ "false",
+ "Indicate wether the UTXO is a coinbase"},
+ {"privatekey", RPCArg::Type::STR,
+ RPCArg::Optional::NO,
+ "private key in base58-encoding"},
+ },
+ },
+ },
+ },
+ },
+ RPCResult{"\"poof\" (string) A string that is a serialized, "
+ "hex-encoded proof data.\n"},
+ RPCExamples{HelpExampleRpc("buildavalancheproof",
+ "0 1234567800 \"<master>\" []")},
+ }
+ .Check(request);
+
+ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM,
+ UniValue::VSTR, UniValue::VARR});
+
+ if (!g_avalanche) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized");
+ }
+
+ const uint64_t sequence = request.params[0].get_int64();
+ const int64_t expiration = request.params[1].get_int64();
+ avalanche::ProofBuilder pb(sequence, expiration,
+ ParsePubKey(request.params[2]));
+
+ const UniValue &stakes = request.params[3].get_array();
+ for (size_t i = 0; i < stakes.size(); i++) {
+ const UniValue &stake = stakes[i];
+ RPCTypeCheckObj(stake,
+ {
+ {"txid", UniValue::VSTR},
+ {"vout", UniValue::VNUM},
+ // "amount" is also required but check is done below
+ // due to UniValue::VNUM erroneously not accepting
+ // quoted numerics (which are valid JSON)
+ {"height", UniValue::VNUM},
+ {"privatekey", UniValue::VSTR},
+ });
+
+ int nOut = find_value(stake, "vout").get_int();
+ if (nOut < 0) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
+ "vout must be positive");
+ }
+
+ const int height = find_value(stake, "height").get_int();
+ if (height < 1) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
+ "height must be positive");
+ }
+
+ const TxId txid(ParseHashO(stake, "txid"));
+ const COutPoint utxo(txid, nOut);
+
+ if (!stake.exists("amount")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount");
+ }
+
+ const Amount amount = AmountFromValue(find_value(stake, "amount"));
+
+ const UniValue &iscbparam = find_value(stake, "iscoinbase");
+ const bool iscoinbase =
+ iscbparam.isNull() ? false : iscbparam.get_bool();
+ CKey key = DecodeSecret(find_value(stake, "privatekey").get_str());
+
+ if (!pb.addUTXO(utxo, amount, uint32_t(height) << 1 | iscoinbase,
+ std::move(key))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid private key");
+ }
+ }
+
+ const avalanche::Proof proof = pb.build();
+
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << proof;
+ return HexStr(ss.begin(), ss.end());
}
// clang-format off
@@ -82,6 +202,7 @@
// ------------------- ------------------------ ---------------------- ----------
{ "avalanche", "getavalanchekey", getavalanchekey, {}},
{ "avalanche", "addavalanchenode", addavalanchenode, {"nodeid"}},
+ { "avalanche", "buildavalancheproof", buildavalancheproof, {"sequence", "expiration", "master", "stakes"}},
};
// clang-format on
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -157,6 +157,7 @@
{"stop", 0, "wait"},
// Avalanche
{"addavalanchenode", 0, "nodeid"},
+ {"buildavalancheproof", 3, "stakes"},
// ABC specific RPC
{"setexcessiveblock", 0, "blockSize"},
};
diff --git a/test/functional/abc_p2p_avalanche.py b/test/functional/abc_p2p_avalanche.py
--- a/test/functional/abc_p2p_avalanche.py
+++ b/test/functional/abc_p2p_avalanche.py
@@ -22,16 +22,6 @@
from test_framework import schnorr
-AVA_HEX_PROOF = (
- "d97587e6c882615796011ec8f9a7b1c64104e556ba887297fd6a655bc2579d26814e8"
- "54c902448ec3ce3c6fe965e3420aa3f0e9611d3c0b8a73b6329741e2e726fd17f5e8a"
- "bd546a614b0e05433528b195870169a79ff23e1d58c64afad42ad81cffe53967e16be"
- "b692fc5776bb442c79c5d91de00cf21804712806594010038e168a34104d9d84ebf65"
- "22cf24c6fd4addedd068632a4db06c3cd6e40031c72d416e9eefbd90037383d8da9e9"
- "213a4818a02f108ac1656141ecfbfdde0aeb8620eb210c08b2ce587d9fec0799f9725"
- "5d2bc5a077c7b4e8ca8a68d6a0377abf0aa2473f97b37779431062dad50ef5fd21cf1"
- "7c0276a293ee5b3f5a130fc5f9b217585cae23e")
-
BLOCK_ACCEPTED = 0
BLOCK_REJECTED = 1
BLOCK_UNKNOWN = -1
@@ -191,10 +181,18 @@
"12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747")
pubkey = schnorr.getpubkey(privkey, compressed=True)
+ privatekey = node.get_deterministic_priv_key().key
+ proof = node.buildavalancheproof(11, 12, pubkey.hex(), [{
+ 'txid': "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747",
+ 'vout': 0,
+ 'amount': 10,
+ 'height': 100,
+ 'privatekey': privatekey,
+ }])
+
# Activate the quorum.
for n in quorum:
- success = node.addavalanchenode(
- n.nodeid, pubkey.hex(), AVA_HEX_PROOF)
+ success = node.addavalanchenode(n.nodeid, pubkey.hex(), proof)
assert success is True
def can_find_block_in_poll(hash, resp=BLOCK_ACCEPTED):
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, May 20, 22:36 (21 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5866074
Default Alt Text
D6914.diff (9 KB)
Attached To
D6914: [avalanche] Add buildavalanchproof RPC call
Event Timeline
Log In to Comment