Skip to content

Commit a3c6738

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 0856f5f commit a3c6738

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>
@@ -16,6 +17,8 @@ extern BlockMap mapBlockIndex;
1617

1718
uint256 BlockUtxoHasher::GetUtxoHash(const CTransaction& tx) const
1819
{
20+
if (as.IsActive(Fork::SegwitLight))
21+
return tx.GetBareTxid();
1922
return tx.GetHash();
2023
}
2124

divi/src/UtxoCheckingAndUpdating.h

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

8+
class ActivationState;
89
class CTransaction;
910
class CValidationState;
1011
class CCoinsViewCache;
@@ -53,8 +54,17 @@ class TransactionUtxoHasher
5354
class BlockUtxoHasher : public TransactionUtxoHasher
5455
{
5556

57+
private:
58+
59+
/** The activation state used for checking on segwit light. */
60+
const ActivationState& as;
61+
5662
public:
5763

64+
explicit BlockUtxoHasher(const ActivationState& a)
65+
: as(a)
66+
{}
67+
5868
uint256 GetUtxoHash(const CTransaction& tx) const override;
5969

6070
};

divi/src/main.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "coins.h"
2121
#include <defaultValues.h>
2222
#include "FeeRate.h"
23+
#include "ForkActivation.h"
2324
#include "init.h"
2425
#include "kernel.h"
2526
#include "libzerocoin/bignum.h"
@@ -1339,7 +1340,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
13391340
LogWalletBalance();
13401341
static const CChainParams& chainParameters = Params();
13411342

1342-
const BlockUtxoHasher utxoHasher;
1343+
const ActivationState as(block);
1344+
const BlockUtxoHasher utxoHasher(as);
13431345

13441346
VerifyBestBlockIsAtPreviousBlock(pindex,view);
13451347
if (block.GetHash() == Params().HashGenesisBlock())
@@ -2638,7 +2640,8 @@ bool static LoadBlockIndexDB(string& strError)
26382640
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";
26392641
return false;
26402642
}
2641-
const BlockUtxoHasher utxoHasher;
2643+
const ActivationState as(block);
2644+
const BlockUtxoHasher utxoHasher(as);
26422645

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

divi/src/rpcblockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ Value gettxout(const Array& params, bool fHelp)
414414
"gettxout \"txid\" n ( includemempool )\n"
415415
"\nReturns details about an unspent transaction output.\n"
416416
"\nArguments:\n"
417-
"1. \"txid\" (string, required) The transaction id\n"
417+
"1. \"txid\" (string, required) The transaction id or bare txid (after segwit-light)\n"
418418
"2. n (numeric, required) vout value\n"
419419
"3. includemempool (boolean, optional) Whether to included the mem pool\n"
420420
"\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
uint256 GetUtxoHash(const CTransaction& tx) const override
373378
{
379+
const ActivationState as(chainActive.Tip());
380+
if (as.IsActive(Fork::SegwitLight))
381+
return tx.GetBareTxid();
374382
return tx.GetHash();
375383
}
376384

0 commit comments

Comments
 (0)