Page MenuHomePhabricator

D1074.id2827.diff
No OneTemporary

D1074.id2827.diff

diff --git a/src/Makefile.test.include b/src/Makefile.test.include
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -98,6 +98,7 @@
test/undo_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp \
+ test/utxocommit_tests.cpp \
test/validation_tests.cpp
if ENABLE_WALLET
diff --git a/src/coins.h b/src/coins.h
--- a/src/coins.h
+++ b/src/coins.h
@@ -56,12 +56,21 @@
template <typename Stream> void Serialize(Stream &s) const {
assert(!IsSpent());
::Serialize(s, VARINT(nHeightAndIsCoinBase));
- ::Serialize(s, CTxOutCompressor(REF(out)));
+ // only compress for disk format
+ if (s.GetType() & SER_DISK) {
+ ::Serialize(s, CTxOutCompressor(REF(out)));
+ } else {
+ ::Serialize(s, REF(out));
+ }
}
template <typename Stream> void Unserialize(Stream &s) {
::Unserialize(s, VARINT(nHeightAndIsCoinBase));
- ::Unserialize(s, REF(CTxOutCompressor(out)));
+ if (s.GetType() & SER_DISK) {
+ ::Unserialize(s, REF(CTxOutCompressor(out)));
+ } else {
+ ::Unserialize(s, REF(out));
+ }
}
size_t DynamicMemoryUsage() const {
diff --git a/src/test/utxocommit_tests.cpp b/src/test/utxocommit_tests.cpp
new file mode 100644
--- /dev/null
+++ b/src/test/utxocommit_tests.cpp
@@ -0,0 +1,124 @@
+// Copyright (c) 2014-2016 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// Tests for CUtxoCommit wrapper.
+// Mostly redundant with libsecp256k1_multiset tests
+
+#include "coins.h"
+#include "test/test_bitcoin.h"
+#include "util.h"
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+#include "secp256k1/include/secp256k1_multiset.h"
+#include "utxocommit.h"
+
+static COutPoint RandomOutpoint() {
+ const COutPoint op(InsecureRand256(), insecure_rand());
+ return op;
+}
+
+static Coin RandomCoin() {
+ const Coin c(CTxOut(Amount(InsecureRandRange(1000)),
+ CScript(InsecureRandBytes(insecure_rand() % 0x3f))),
+ insecure_rand(), InsecureRandBool());
+ return c;
+}
+
+BOOST_FIXTURE_TEST_SUITE(utxocommit_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(utxo_commit_order) {
+
+ // Test order independence
+
+ const COutPoint op1 = RandomOutpoint();
+ const COutPoint op2 = RandomOutpoint();
+ const COutPoint op3 = RandomOutpoint();
+ const Coin c1 = RandomCoin();
+ const Coin c2 = RandomCoin();
+ const Coin c3 = RandomCoin();
+
+ CUtxoCommit uc1, uc2, uc3;
+ BOOST_CHECK(uc1 == uc2);
+ uc1.Add(op1, c1);
+ uc1.Add(op2, c2);
+ uc1.Add(op3, c3);
+
+ uc2.Add(op2, c2);
+ BOOST_CHECK(uc1 != uc2);
+ uc2.Add(op3, c3);
+ uc2.Add(op1, c1);
+ BOOST_CHECK(uc1 == uc2);
+
+ // remove ordering
+ uc2.Remove(op2, c2);
+ uc2.Remove(op3, c3);
+
+ uc1.Remove(op2, c2);
+ uc1.Remove(op3, c3);
+
+ BOOST_CHECK(uc1 == uc2);
+
+ // odd but allowed
+ uc3.Remove(op2, c2);
+ uc3.Add(op2, c2);
+ uc3.Add(op1, c1);
+ BOOST_CHECK(uc1 == uc3);
+}
+
+BOOST_AUTO_TEST_CASE(utxo_commit_serialize) {
+
+ // Test whether the serialization is as expected
+
+ // some coin & output
+ const std::vector<uint8_t> txid = ParseHex(
+ "38115d014104c6ec27cffce0823c3fecb162dbd576c88dd7cda0b7b32b096118");
+ const uint32_t output = 2;
+ const uint32_t height = 7;
+ const uint64_t amount = 100;
+
+ const auto script =
+ CScript(ParseHex("76A9148ABCDEFABBAABBAABBAABBAABBAABBAABBAABBA88AC"));
+
+ const COutPoint op(uint256(txid), output);
+ const Coin coin = Coin(CTxOut(Amount(amount), script), height, false);
+ CScript s;
+
+ // find commit
+ CUtxoCommit commit;
+ commit.Add(op, coin);
+ uint256 hash = commit.GetHash();
+
+ // try the same manually
+ std::vector<uint8_t> expected;
+
+ // txid
+ expected.insert(expected.end(), txid.begin(), txid.end());
+
+ // output
+ auto outputbytes = ParseHex("02000000");
+ expected.insert(expected.end(), outputbytes.begin(), outputbytes.end());
+
+ // height and coinbase => height * 2
+ expected.push_back(14);
+
+ // amount & script
+ auto amountbytes = ParseHex("6400000000000000");
+ expected.insert(expected.end(), amountbytes.begin(), amountbytes.end());
+ expected.push_back(uint8_t(script.size()));
+ expected.insert(expected.end(), script.begin(), script.end());
+
+ secp256k1_multiset multiset;
+ secp256k1_multiset_init(context, &multiset);
+ secp256k1_multiset_add(context, &multiset, expected.data(),
+ expected.size());
+
+ std::vector<uint8_t> expectedhash(32);
+ secp256k1_multiset_finalize(context, expectedhash.data(), &multiset);
+
+ BOOST_ASSERT(uint256(expectedhash) == hash);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/utxocommit.h b/src/utxocommit.h
new file mode 100644
--- /dev/null
+++ b/src/utxocommit.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2017 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTXOCOMMIT_H
+#define BITCOIN_UTXOCOMMIT_H
+
+#include "coins.h"
+#include "hash.h"
+#include "secp256k1/include/secp256k1_multiset.h"
+#include "streams.h"
+#include <vector>
+
+secp256k1_context *context = nullptr;
+
+/* A Utxo Commitment
+ *
+ * This is maintained as 96-byte multiset value that uniquely defines a UTXO set
+ *
+ * It wraps the secp256k1 multiset
+ *
+ * Note that a CUtxoCommit allows "negative sets". That is
+ *
+ * CUtxoCommit set; // set is an empty set
+ * set.Remove(X); // set is empty set "minus" X
+ * set.Add(X); // set is an empty set
+ *
+ * This means a CUtxoCommit can both represent the total UTXO set, or a delta to
+ * the UTXO set
+*/
+class CUtxoCommit {
+private:
+ secp256k1_multiset multiset;
+
+public:
+ // Constructs empty CUtxoCommit
+ CUtxoCommit() { secp256k1_multiset_init(context, &multiset); }
+
+ // Construct by combining two other CUtxoCommits
+ CUtxoCommit(const CUtxoCommit &commit1, const CUtxoCommit &commit2)
+ : CUtxoCommit() {
+ secp256k1_multiset_combine(context, &this->multiset, &commit1.multiset);
+ secp256k1_multiset_combine(context, &this->multiset, &commit2.multiset);
+ }
+
+ // Adds a TXO from multiset
+ void Add(const COutPoint &out, const Coin &element) {
+
+ CDataStream txo(SER_NETWORK, PROTOCOL_VERSION);
+ txo << out << element;
+ secp256k1_multiset_add(context, &multiset, (const uint8_t *)&txo[0],
+ txo.size());
+ }
+
+ // Removes a TXO from multiset
+ void Remove(const COutPoint &out, const Coin &element) {
+
+ CDataStream txo(SER_NETWORK, PROTOCOL_VERSION);
+ txo << out << element;
+ secp256k1_multiset_remove(context, &multiset, (const uint8_t *)&txo[0],
+ txo.size());
+ }
+
+ uint256 GetHash() const {
+
+ std::vector<uint8_t> hash(32);
+ secp256k1_multiset_finalize(context, hash.data(), &multiset);
+ return uint256(hash);
+ }
+
+ // Comparison
+ friend bool operator==(const CUtxoCommit &a, const CUtxoCommit &b) {
+ return a.GetHash() == b.GetHash();
+ }
+ friend bool operator!=(const CUtxoCommit &a, const CUtxoCommit &b) {
+ return a.GetHash() != b.GetHash();
+ }
+};
+
+#endif // MULTISET_H

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 26, 12:04 (2 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573496
Default Alt Text
D1074.id2827.diff (7 KB)

Event Timeline