Skip to content

Commit 62f45a0

Browse files
committed
Consensus and mempool parts of segwit-light.
This implements "segwit-light" in the node (consensus and mempool): After activation of a new fork, outputs created by new transactions are referred to by the creating transaction's bare txid rather than the normal hash (txid). This makes chains of constructed transactions immune to transaction malleability. In the mempool, we use the current chain tip to determine the activation state of the fork, as we can't know for sure when a transaction will be confirmed (and thus what activation state will be in effect then). This will lead to issues right around the fork activation time, but we will simply disallow spending of unconfirmed outputs in the mempool and wallet "around" the fork time temporarily to resolve this. The wallet is also not yet updated to take the change into account when selecting coins.
1 parent a417b1b commit 62f45a0

9 files changed

+45
-10
lines changed

divi/src/ActiveChainManager.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <chain.h>
66
#include <coins.h>
77
#include <BlockUndo.h>
8+
#include <ForkActivation.h>
89
#include <Logging.h>
910
#include <addressindex.h>
1011
#include <txdb.h>
@@ -87,7 +88,8 @@ bool ActiveChainManager::DisconnectBlock(
8788
return error("DisconnectBlock() : block and undo data inconsistent");
8889
}
8990

90-
const BlockUtxoHasher utxoHasher;
91+
const ActivationState as(pindex);
92+
const BlockUtxoHasher utxoHasher(as);
9193

9294
bool fClean = true;
9395
IndexDatabaseUpdates indexDBUpdates;

divi/src/ForkActivation.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ const std::unordered_map<Fork, int64_t,std::hash<int>> ACTIVATION_TIMES = {
2525
{Fork::TestByTimestamp, 1000000000},
2626
{Fork::HardenedStakeModifier, unixTimestampForDec31stMidnight},
2727
{Fork::UniformLotteryWinners, unixTimestampForDec31stMidnight},
28+
/* FIXME: Set real activation time for segwit light. It is after
29+
staking vaults. */
30+
{Fork::SegwitLight, 2000000000},
2831
};
2932

3033
} // anonymous namespace
3134

3235
ActivationState::ActivationState(const CBlockIndex* pi)
33-
: nTime(pi->nTime)
36+
: nTime(pi == nullptr ? 0 : pi->nTime)
3437
{}
3538

3639
ActivationState::ActivationState(const CBlockHeader& block)

divi/src/ForkActivation.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,18 @@ class CBlockIndex;
1818
*/
1919
enum Fork
2020
{
21-
/* Test forks not actually deployed / active but used for unit tests. */
22-
TestByTimestamp,
2321
HardenedStakeModifier,
2422
UniformLotteryWinners,
23+
24+
/**
25+
* Start of "segwit light": The UTXOs created by transactions from after
26+
* the fork will be indexed by a "bare txid", which does not include
27+
* any signature data. This fixes transaction malleability.
28+
*/
29+
SegwitLight,
30+
31+
/* Test forks not actually deployed / active but used for unit tests. */
32+
TestByTimestamp,
2533
};
2634

2735
/**

divi/src/UtxoCheckingAndUpdating.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <UtxoCheckingAndUpdating.h>
22

3+
#include <ForkActivation.h>
34
#include <primitives/transaction.h>
45
#include <Logging.h>
56
#include <coins.h>
@@ -14,6 +15,8 @@
1415

1516
OutputHash BlockUtxoHasher::GetUtxoHash(const CTransaction& tx) const
1617
{
18+
if (as.IsActive(Fork::SegwitLight))
19+
return OutputHash(tx.GetBareTxid());
1720
return OutputHash(tx.GetHash());
1821
}
1922

divi/src/UtxoCheckingAndUpdating.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <amount.h>
88
#include <uint256.h>
99

10+
class ActivationState;
1011
class BlockMap;
1112
class CTransaction;
1213
class CValidationState;
@@ -56,8 +57,17 @@ class TransactionUtxoHasher
5657
class BlockUtxoHasher : public TransactionUtxoHasher
5758
{
5859

60+
private:
61+
62+
/** The activation state used for checking on segwit light. */
63+
const ActivationState& as;
64+
5965
public:
6066

67+
explicit BlockUtxoHasher(const ActivationState& a)
68+
: as(a)
69+
{}
70+
6171
OutputHash GetUtxoHash(const CTransaction& tx) const override;
6272

6373
};

divi/src/main.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "coins.h"
2222
#include <defaultValues.h>
2323
#include "FeeRate.h"
24+
#include "ForkActivation.h"
2425
#include "init.h"
2526
#include "kernel.h"
2627
#include "libzerocoin/bignum.h"
@@ -1074,7 +1075,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
10741075
LogWalletBalance();
10751076
static const CChainParams& chainParameters = Params();
10761077

1077-
const BlockUtxoHasher utxoHasher;
1078+
const ActivationState as(block);
1079+
const BlockUtxoHasher utxoHasher(as);
10781080

10791081
VerifyBestBlockIsAtPreviousBlock(pindex,view);
10801082
if (block.GetHash() == Params().HashGenesisBlock())
@@ -2346,7 +2348,8 @@ bool static LoadBlockIndexDB(string& strError)
23462348
strError = "The wallet has been not been closed gracefully and has caused corruption of blocks stored to disk. Data directory is in an unusable state";
23472349
return false;
23482350
}
2349-
const BlockUtxoHasher utxoHasher;
2351+
const ActivationState as(block);
2352+
const BlockUtxoHasher utxoHasher(as);
23502353

23512354
std::vector<CTxUndo> vtxundo;
23522355
vtxundo.reserve(block.vtx.size() - 1);

divi/src/rpcblockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ Value gettxout(const Array& params, bool fHelp)
415415
"gettxout \"txid\" n ( includemempool )\n"
416416
"\nReturns details about an unspent transaction output.\n"
417417
"\nArguments:\n"
418-
"1. \"txid\" (string, required) The transaction id\n"
418+
"1. \"txid\" (string, required) The transaction id or bare txid (after segwit-light)\n"
419419
"2. n (numeric, required) vout value\n"
420420
"3. includemempool (boolean, optional) Whether to included the mem pool\n"
421421
"\nResult:\n"

divi/src/test/wallet_coinmanagement_tests.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,7 @@ BOOST_AUTO_TEST_CASE(willUseUtxoHashForSpendingCoins)
453453
wallet.FakeAddToChain(wtx);
454454

455455
const CScript sendTo = CScript() << OP_TRUE;
456-
std::string strError;
457456
CReserveKey reserveKey(wallet);
458-
CAmount nFeeRequired;
459457
CWalletTx wtxNew;
460458
BOOST_CHECK(wallet.CreateTransaction({{sendTo, COIN / 10}}, wtxNew, reserveKey, ALL_SPENDABLE_COINS, nullptr).second);
461459

divi/src/txmempool.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "txmempool.h"
88

99
#include "clientversion.h"
10+
#include "ForkActivation.h"
1011
#include "main.h"
1112
#include "streams.h"
1213
#include "Logging.h"
@@ -363,14 +364,21 @@ class CMinerPolicyEstimator
363364
namespace
364365
{
365366

366-
/** The UTXO hasher used in mempool logic. */
367+
/** The UTXO hasher used in mempool logic. It uses the state of segwit-light
368+
* based on the latest chain tip (since we can't know when a particular
369+
* transaction will be confirmed / what the real activation state will be then).
370+
* Spending of unconfirmed change around the fork will be discouraged by
371+
* policy, so that this should not be an issue in practice. */
367372
class MempoolUtxoHasher : public TransactionUtxoHasher
368373
{
369374

370375
public:
371376

372377
OutputHash GetUtxoHash(const CTransaction& tx) const override
373378
{
379+
const ActivationState as(chainActive.Tip());
380+
if (as.IsActive(Fork::SegwitLight))
381+
return OutputHash(tx.GetBareTxid());
374382
return OutputHash(tx.GetHash());
375383
}
376384

0 commit comments

Comments
 (0)