From 89339ef08b53a9fa9e991d99525b084bbabf6b81 Mon Sep 17 00:00:00 2001 From: Luke Alonso Date: Wed, 7 Feb 2018 18:50:12 -0800 Subject: [PATCH] Initial representative weights for bootstrapping --- CMakeLists.txt | 10 +++++++ ci/record_rep_weights.py | 63 +++++++++++++++++++++++++++++++++++++++ rai/core_test/ledger.cpp | 35 ++++++++++++++++++++++ rai/node/node.cpp | 31 +++++++++++++++++++ rai/secure.cpp | 19 +++++++++++- rai/secure.hpp | 3 ++ rep_weights.bin | Bin 0 -> 3280 bytes 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 ci/record_rep_weights.py create mode 100644 rep_weights.bin diff --git a/CMakeLists.txt b/CMakeLists.txt index 56ce77fb..0100f416 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,8 +230,18 @@ else () error ("Unknown platform: ${CMAKE_SYSTEM_NAME}") endif () +# Embed bootstrap representative weights in executable +file (READ rep_weights.bin filedata HEX) +string (REGEX REPLACE "(..)" "0x\\1," filedata ${filedata}) +file (WRITE ${CMAKE_BINARY_DIR}/bootstrap_weights.cpp "#include \n\ + namespace rai {\n\ + unsigned char rai_bootstrap_weights[] = {${filedata} 0x00};\n\ + size_t rai_bootstrap_weights_size = sizeof(rai_bootstrap_weights) - 1;\n\ + }\n") + add_library (secure ${PLATFORM_SECURE_SOURCE} + ${CMAKE_BINARY_DIR}/bootstrap_weights.cpp rai/config.hpp rai/secure.cpp rai/secure.hpp diff --git a/ci/record_rep_weights.py b/ci/record_rep_weights.py new file mode 100644 index 00000000..996b262b --- /dev/null +++ b/ci/record_rep_weights.py @@ -0,0 +1,63 @@ +import requests +import argparse +import string +from binascii import unhexlify +from base64 import b32decode +from binascii import hexlify, unhexlify + + +parser = argparse.ArgumentParser(description='Generate bootstrap representative weight file.') +parser.add_argument("output", type=str, help="output weight file") +parser.add_argument("--rpc", help="node rpc host:port", default="http://[::1]:7076") +parser.add_argument("--limit", help="percentage of the active supply represented", default=0.99) +parser.add_argument("--cutoff", help="stop using bootstrap reps this many blocks before the current block height", default=250000) +args = parser.parse_args() + +r = requests.post(args.rpc, data='{"action":"representatives"}') +p = r.json() + +reps = [ ] +tbl = string.maketrans('13456789abcdefghijkmnopqrstuwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567') +for acc in p["representatives"]: + reps.append({ + 'account': acc, + 'weight': long(p["representatives"][acc]) + }) + +r = requests.post(args.rpc, data='{"action":"block_count"}') +p = r.json() +block_height = max(0, int(p["count"]) - args.cutoff) + +print "cutoff block height is %d" % block_height + +reps.sort(key=lambda x: x["weight"], reverse=True) + +supplymax = long(0) +for rep in reps: + supplymax += rep["weight"] + +supplymax /= long('1000000000000000000000000000000') +supplymax = long(supplymax * args.limit) +supplymax *= long('1000000000000000000000000000000') + +with open(args.output, 'wb') as of: + of.write(unhexlify("%032X" % block_height)) + + total = long(0) + count = 0 + for rep in reps: + if rep["weight"] == 0: + break + acc_val = long(hexlify(b32decode(rep["account"].encode("utf-8").replace("xrb_", "").translate(tbl) + "====")), 16) + acc_bytes = unhexlify("%064X" % (((acc_val >> 36) & ((1 << 256) - 1)))) + weight_bytes = unhexlify("%032X" % rep["weight"]) + of.write(acc_bytes) + of.write(weight_bytes) + total += rep["weight"] + count += 1 + if total >= supplymax: + break + + print "wrote %d rep weights" % count + + of.close() diff --git a/rai/core_test/ledger.cpp b/rai/core_test/ledger.cpp index 3451a858..967ba2c3 100644 --- a/rai/core_test/ledger.cpp +++ b/rai/core_test/ledger.cpp @@ -1431,3 +1431,38 @@ TEST (ledger, send_open_receive_rollback) ASSERT_EQ (0, ledger.weight (transaction, key3.pub)); ASSERT_EQ (rai::genesis_amount - 0, ledger.weight (transaction, rai::test_genesis_key.pub)); } + +TEST (ledger, bootstrap_rep_weight) +{ + bool init (false); + rai::block_store store (init, rai::unique_path ()); + ASSERT_TRUE (!init); + rai::ledger ledger (store, 40); + rai::account_info info1; + rai::keypair key2; + rai::genesis genesis; + { + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info1)); + rai::send_block send (info1.head, key2.pub, std::numeric_limits::max () - 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ledger.process (transaction, send); + } + { + rai::transaction transaction (store.environment, nullptr, false); + ledger.bootstrap_weight_max_blocks = 3; + ledger.bootstrap_weights[key2.pub] = 1000; + ASSERT_EQ (1000, ledger.weight (transaction, key2.pub)); + } + { + rai::transaction transaction (store.environment, nullptr, true); + genesis.initialize (transaction, store); + ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info1)); + rai::send_block send (info1.head, key2.pub, std::numeric_limits::max () - 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0); + ledger.process (transaction, send); + } + { + rai::transaction transaction (store.environment, nullptr, false); + ASSERT_EQ (0, ledger.weight (transaction, key2.pub)); + } +} diff --git a/rai/node/node.cpp b/rai/node/node.cpp index f341bdb9..b51c0f3a 100644 --- a/rai/node/node.cpp +++ b/rai/node/node.cpp @@ -1525,6 +1525,37 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); }) genesis.initialize (transaction, store); } } + if (rai::rai_network == rai::rai_networks::rai_live_network) + { + extern const char rai_bootstrap_weights[]; + extern const size_t rai_bootstrap_weights_size; + rai::bufferstream weight_stream ((const uint8_t *)rai_bootstrap_weights, rai_bootstrap_weights_size); + rai::uint128_union block_height; + if (!rai::read (weight_stream, block_height)) + { + auto max_blocks = (uint64_t)block_height.number (); + rai::transaction transaction (store.environment, nullptr, false); + if (ledger.store.block_count (transaction).sum () < max_blocks) + { + ledger.bootstrap_weight_max_blocks = max_blocks; + while (true) + { + rai::account account; + if (rai::read (weight_stream, account.bytes)) + { + break; + } + rai::amount weight; + if (rai::read (weight_stream, weight.bytes)) + { + break; + } + BOOST_LOG (log) << "Using bootstrap rep weight: " << account.to_account () << " -> " << weight.format_balance (Mxrb_ratio, 0, true) << " XRB"; + ledger.bootstrap_weights[account] = weight.number (); + } + } + } + } } rai::node::~node () diff --git a/rai/secure.cpp b/rai/secure.cpp index af390937..216846a5 100644 --- a/rai/secure.cpp +++ b/rai/secure.cpp @@ -219,7 +219,8 @@ rai::keypair::keypair (std::string const & prv_a) rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a) : store (store_a), -inactive_supply (inactive_supply_a) +inactive_supply (inactive_supply_a), +check_bootstrap_weights (true) { } @@ -2424,6 +2425,22 @@ std::string rai::ledger::block_text (rai::block_hash const & hash_a) // Vote weight of an account rai::uint128_t rai::ledger::weight (MDB_txn * transaction_a, rai::account const & account_a) { + if (check_bootstrap_weights.load ()) + { + auto blocks = store.block_count (transaction_a); + if (blocks.sum () < bootstrap_weight_max_blocks) + { + auto weight = bootstrap_weights.find (account_a); + if (weight != bootstrap_weights.end ()) + { + return weight->second; + } + } + else + { + check_bootstrap_weights = false; + } + } return store.representation_get (transaction_a, account_a); } diff --git a/rai/secure.hpp b/rai/secure.hpp index a37264ae..ca96e716 100644 --- a/rai/secure.hpp +++ b/rai/secure.hpp @@ -390,6 +390,9 @@ public: static rai::uint128_t const unit; rai::block_store & store; rai::uint128_t inactive_supply; + std::unordered_map bootstrap_weights; + uint64_t bootstrap_weight_max_blocks; + std::atomic check_bootstrap_weights; }; extern rai::keypair const & zero_key; extern rai::keypair const & test_genesis_key; diff --git a/rep_weights.bin b/rep_weights.bin new file mode 100644 index 0000000000000000000000000000000000000000..daa9206e0d05a19fd7de8b5cd18c0c9fe0690087 GIT binary patch literal 3280 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