Bitcoin ABC  0.22.12
P2P Digital Currency
avalanche.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 #include <avalanche/processor.h>
7 #include <avalanche/proof.h>
9 #include <config.h>
10 #include <key_io.h>
11 #include <rpc/server.h>
12 #include <rpc/util.h>
13 #include <util/strencodings.h>
14 
15 #include <univalue.h>
16 
17 static UniValue getavalanchekey(const Config &config,
18  const JSONRPCRequest &request) {
19  RPCHelpMan{
20  "getavalanchekey",
21  "Returns the key used to sign avalanche messages.\n",
22  {},
24  RPCExamples{HelpExampleRpc("getavalanchekey", "")},
25  }
26  .Check(request);
27 
28  if (!g_avalanche) {
29  throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized");
30  }
31 
32  return HexStr(g_avalanche->getSessionPubKey());
33 }
34 
35 static CPubKey ParsePubKey(const UniValue &param) {
36  const std::string keyHex = param.get_str();
37  if ((keyHex.length() != 2 * CPubKey::COMPRESSED_SIZE &&
38  keyHex.length() != 2 * CPubKey::SIZE) ||
39  !IsHex(keyHex)) {
41  strprintf("Invalid public key: %s\n", keyHex));
42  }
43 
44  return HexToPubKey(keyHex);
45 }
46 
47 static UniValue addavalanchenode(const Config &config,
48  const JSONRPCRequest &request) {
49  RPCHelpMan{
50  "addavalanchenode",
51  "Add a node in the set of peers to poll for avalanche.\n",
52  {
54  "Node to be added to avalanche."},
56  "The public key of the node."},
58  "Proof that the node is not a sybil."},
59  },
61  "Whether the addition succeeded or not."},
63  HelpExampleRpc("addavalanchenode", "5, \"<pubkey>\", \"<proof>\"")},
64  }
65  .Check(request);
66 
67  RPCTypeCheck(request.params,
68  {UniValue::VNUM, UniValue::VSTR, UniValue::VSTR});
69 
70  if (!g_avalanche) {
71  throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized");
72  }
73 
74  const NodeId nodeid = request.params[0].get_int64();
75  const CPubKey key = ParsePubKey(request.params[1]);
76 
77  CDataStream ss(ParseHexV(request.params[2], "proof"), SER_NETWORK,
79  avalanche::Proof proof;
80  ss >> proof;
81 
82  if (key != proof.getMaster()) {
83  // TODO: we want to provide a proper delegation.
84  return false;
85  }
86 
87  return g_avalanche->addNode(nodeid, proof,
88  avalanche::DelegationBuilder(proof).build());
89 }
90 
91 static UniValue buildavalancheproof(const Config &config,
92  const JSONRPCRequest &request) {
93  RPCHelpMan{
94  "buildavalancheproof",
95  "Build a proof for avalanche's sybil resistance.\n",
96  {
98  "The proof's sequence"},
100  "A timestamp indicating when the proof expire"},
102  "The master public key"},
103  {
104  "stakes",
107  "The stakes to be signed and associated private keys",
108  {
109  {
110  "stake",
113  "A stake to be attached to this proof",
114  {
115  {"txid", RPCArg::Type::STR_HEX,
116  RPCArg::Optional::NO, "The transaction id"},
118  "The output number"},
119  {"amount", RPCArg::Type::AMOUNT,
120  RPCArg::Optional::NO, "The amount in this UTXO"},
122  "The height at which this UTXO was mined"},
123  {"iscoinbase", RPCArg::Type::BOOL,
124  /* default */ "false",
125  "Indicate wether the UTXO is a coinbase"},
126  {"privatekey", RPCArg::Type::STR,
128  "private key in base58-encoding"},
129  },
130  },
131  },
132  },
133  },
135  "A string that is a serialized, hex-encoded proof data."},
136  RPCExamples{HelpExampleRpc("buildavalancheproof",
137  "0 1234567800 \"<master>\" []")},
138  }
139  .Check(request);
140 
141  RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM,
142  UniValue::VSTR, UniValue::VARR});
143 
144  if (!g_avalanche) {
145  throw JSONRPCError(RPC_INTERNAL_ERROR, "Avalanche is not initialized");
146  }
147 
148  const uint64_t sequence = request.params[0].get_int64();
149  const int64_t expiration = request.params[1].get_int64();
150  avalanche::ProofBuilder pb(sequence, expiration,
151  ParsePubKey(request.params[2]));
152 
153  const UniValue &stakes = request.params[3].get_array();
154  for (size_t i = 0; i < stakes.size(); i++) {
155  const UniValue &stake = stakes[i];
156  RPCTypeCheckObj(stake,
157  {
158  {"txid", UniValue::VSTR},
159  {"vout", UniValue::VNUM},
160  // "amount" is also required but check is done below
161  // due to UniValue::VNUM erroneously not accepting
162  // quoted numerics (which are valid JSON)
163  {"height", UniValue::VNUM},
164  {"privatekey", UniValue::VSTR},
165  });
166 
167  int nOut = find_value(stake, "vout").get_int();
168  if (nOut < 0) {
170  "vout must be positive");
171  }
172 
173  const int height = find_value(stake, "height").get_int();
174  if (height < 1) {
176  "height must be positive");
177  }
178 
179  const TxId txid(ParseHashO(stake, "txid"));
180  const COutPoint utxo(txid, nOut);
181 
182  if (!stake.exists("amount")) {
183  throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing amount");
184  }
185 
186  const Amount amount = AmountFromValue(find_value(stake, "amount"));
187 
188  const UniValue &iscbparam = find_value(stake, "iscoinbase");
189  const bool iscoinbase =
190  iscbparam.isNull() ? false : iscbparam.get_bool();
191  CKey key = DecodeSecret(find_value(stake, "privatekey").get_str());
192 
193  if (!pb.addUTXO(utxo, amount, uint32_t(height), iscoinbase,
194  std::move(key))) {
195  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid private key");
196  }
197  }
198 
199  const avalanche::Proof proof = pb.build();
200 
202  ss << proof;
203  return HexStr(ss.begin(), ss.end());
204 }
205 
207  // clang-format off
208  static const CRPCCommand commands[] = {
209  // category name actor (function) argNames
210  // ------------------- ------------------------ ---------------------- ----------
211  { "avalanche", "getavalanchekey", getavalanchekey, {}},
212  { "avalanche", "addavalanchenode", addavalanchenode, {"nodeid"}},
213  { "avalanche", "buildavalancheproof", buildavalancheproof, {"sequence", "expiration", "master", "stakes"}},
214  };
215  // clang-format on
216 
217  for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) {
218  t.appendCommand(commands[vcidx].name, &commands[vcidx]);
219  }
220 }
void RegisterAvalancheRPCCommands(CRPCTable &t)
Register Avalanche RPC commands.
Definition: avalanche.cpp:206
static UniValue addavalanchenode(const Config &config, const JSONRPCRequest &request)
Definition: avalanche.cpp:47
static constexpr unsigned int SIZE
secp256k1:
Definition: pubkey.h:36
Bitcoin RPC command dispatcher.
Definition: server.h:198
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Check for expected keys/value types in an Object.
Definition: util.cpp:52
bool get_bool() const
static Amount AmountFromValue(const UniValue &value)
Definition: bitcoin-tx.cpp:562
Required arg.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1201
#define ARRAYLEN(array)
Utilities for converting data from/to strings.
Definition: strencodings.h:19
Definition: amount.h:17
CPubKey HexToPubKey(const std::string &hex_in)
Definition: util.cpp:153
const std::string & get_str() const
const UniValue & get_array() const
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:196
int64_t get_int64() const
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:120
bool appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:316
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
static CPubKey ParsePubKey(const UniValue &param)
Definition: avalanche.cpp:35
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:234
Special type that is a STR with only hex chars.
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:143
uint256 ParseHashO(const UniValue &o, std::string strKey)
Definition: util.cpp:116
static constexpr unsigned int COMPRESSED_SIZE
Definition: pubkey.h:37
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:52
Definition: config.h:19
Special string with only hex chars.
UniValue params
Definition: request.h:37
const char * name
Definition: rest.cpp:43
bool exists(const std::string &key) const
Definition: univalue.h:87
std::unique_ptr< avalanche::Processor > g_avalanche
Global avalanche instance.
Definition: processor.cpp:28
An encapsulated public key.
Definition: pubkey.h:31
static UniValue buildavalancheproof(const Config &config, const JSONRPCRequest &request)
Definition: avalanche.cpp:91
bool IsHex(const std::string &str)
Returns true if each character in str is a hex character, and has an even number of hex digits...
bool addUTXO(COutPoint utxo, Amount amount, uint32_t height, bool is_coinbase, CKey key)
int64_t NodeId
Definition: net.h:111
int get_int() const
Invalid address or key.
Definition: protocol.h:42
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
bool isNull() const
Definition: univalue.h:89
const_iterator end() const
Definition: streams.h:277
const_iterator begin() const
Definition: streams.h:275
A TxId is the identifier of a transaction.
Definition: txid.h:14
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
Special type representing a floating point amount (can be either NUM or STR)
std::string HexStr(const T itbegin, const T itend)
Definition: strencodings.h:132
static UniValue getavalanchekey(const Config &config, const JSONRPCRequest &request)
Definition: avalanche.cpp:17
size_t size() const
Definition: univalue.h:80
An encapsulated secp256k1 private key.
Definition: key.h:25
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:80
Error parsing or validating structure in raw format.
Definition: protocol.h:50
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:25