Skip to content

Commit

Permalink
Randomise winning anchor on blockhash
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed Apr 13, 2021
1 parent db46ddb commit 8e9d93e
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 104 deletions.
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class CMainParams : public CChainParams {
consensus.ClarkeQuayHeight = 595738;
consensus.DakotaHeight = 678000; // 1st March 2021
consensus.DakotaCrescentHeight = 733000; // 25th March 2021
consensus.EunosHeight = std::numeric_limits<int>::max();

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -305,6 +306,7 @@ class CTestNetParams : public CChainParams {
consensus.ClarkeQuayHeight = 155000;
consensus.DakotaHeight = 220680;
consensus.DakotaCrescentHeight = 287700;
consensus.EunosHeight = std::numeric_limits<int>::max();

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
// consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down Expand Up @@ -454,6 +456,7 @@ class CDevNetParams : public CChainParams {
consensus.ClarkeQuayHeight = 0;
consensus.DakotaHeight = 0;
consensus.DakotaCrescentHeight = 0;
consensus.EunosHeight = 0;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.pos.nTargetTimespan = 5 * 60; // 5 min == 10 blocks
Expand Down Expand Up @@ -595,6 +598,7 @@ class CRegTestParams : public CChainParams {
consensus.ClarkeQuayHeight = 10000000;
consensus.DakotaHeight = 10000000;
consensus.DakotaCrescentHeight = 10000000;
consensus.EunosHeight = 10000000;

consensus.pos.diffLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.pos.nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
Expand Down
2 changes: 2 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ struct Params {
int DakotaHeight;
/** Fifth major fork **/
int DakotaCrescentHeight;
/** Sixth major fork **/
int EunosHeight;
/** Foundation share after AMK, normalized to COIN = 100% */
CAmount foundationShareDFIP1;

Expand Down
59 changes: 47 additions & 12 deletions src/masternodes/anchors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ std::unique_ptr<CAnchorAwaitingConfirms> panchorAwaitingConfirms;

static const char DB_ANCHORS = 'A';
static const char DB_PENDING = 'p';
static const char DB_BITCOININDEX = 'Z'; // Bitcoin height to blockhash table

template <typename TContainer>
bool CheckSigs(uint256 const & sigHash, TContainer const & sigs, std::set<CKeyID> const & keys)
Expand Down Expand Up @@ -526,7 +527,7 @@ void CAnchorIndex::CheckPendingAnchors()
{
AssertLockHeld(cs_main);

std::set<AnchorRec, decltype(OrderPendingAnchors)> anchorsPending(OrderPendingAnchors);
spv::PendingSet anchorsPending(spv::PendingOrder);
ForEachPending([&anchorsPending](uint256 const &, AnchorRec & rec) {
anchorsPending.insert(rec);
});
Expand All @@ -546,11 +547,12 @@ void CAnchorIndex::CheckPendingAnchors()
continue;
}

uint32_t timestamp = spv::pspv->ReadTxTimestamp(rec.txHash);
auto blockHeight = spv::pspv->ReadTxBlockHeight(rec.txHash);
const auto timestamp = spv::pspv->ReadTxTimestamp(rec.txHash);
const auto blockHeight = spv::pspv->ReadTxBlockHeight(rec.txHash);
const auto blockHash = panchors->ReadBlockHash(rec.btcHeight);

// Do not delete, TX time still pending. If block height is set to max we cannot trust the timestamp.
if (timestamp == 0 || blockHeight == std::numeric_limits<int32_t>::max()) {
if (timestamp == 0 || blockHeight == std::numeric_limits<int32_t>::max() || blockHash == uint256()) {
continue;
}

Expand Down Expand Up @@ -652,14 +654,7 @@ CAnchorIndex::AnchorRec const * BestOfTwo(CAnchorIndex::AnchorRec const * a1, CA
if (a2 == nullptr)
return a1;

if (a1->anchor.height > a2->anchor.height)
return a1;
else if (a1->anchor.height < a2->anchor.height)
return a2;
// if heights are equal, return anchor with less btc tx hash
else if (a1->txHash < a2->txHash)
return a1;
return a2;
return spv::PendingOrder(*a1, *a2) ? a1 : a2;
}

/// @returns true if top active anchor has been changed
Expand Down Expand Up @@ -754,6 +749,19 @@ bool CAnchorIndex::DeletePendingByBtcTx(uint256 const & btcTxHash)
return false;
}

bool CAnchorIndex::WriteBlock(const uint32_t height, const uint256& blockHash)
{
// Store Bitcoin block index
return db->Write(std::make_pair(DB_BITCOININDEX, height), blockHash);
}

uint256 CAnchorIndex::ReadBlockHash(const uint32_t& height)
{
uint256 blockHash;
db->Read(std::make_pair(DB_BITCOININDEX, height), blockHash);
return blockHash;
}

void CAnchorIndex::ForEachPending(std::function<void (uint256 const &, AnchorRec &)> callback)
{
AssertLockHeld(cs_main);
Expand Down Expand Up @@ -1152,3 +1160,30 @@ bool GetAnchorEmbeddedData(const CKeyID& data, uint64_t& anchorCreationHeight, s

return true;
}

namespace spv
{
const PendingOrderType PendingOrder = PendingOrderType([](const CAnchorIndex::AnchorRec& a, const CAnchorIndex::AnchorRec& b)
{
if (a.btcHeight == b.btcHeight)
{
if (a.anchor.height == b.anchor.height)
{
if (a.anchor.height >= static_cast<THeight>(Params().GetConsensus().EunosHeight))
{
const auto blockHash = panchors->ReadBlockHash(a.btcHeight);
auto aHash = Hash(a.txHash.begin(), a.txHash.end(), blockHash.begin(), blockHash.end());
auto bHash = Hash(b.txHash.begin(), b.txHash.end(), blockHash.begin(), blockHash.end());
return aHash < bHash;
}

return a.txHash < b.txHash;
}

// Higher DeFi comes first
return a.anchor.height > b.anchor.height;
}

return a.btcHeight < b.btcHeight;
});
}
26 changes: 12 additions & 14 deletions src/masternodes/anchors.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ class CAnchorIndex
// Used to apply chain context to post-fork anchors which get added to pending.
void CheckPendingAnchors();

// Store and read Bitcoin block hash by height, used in BestOfTwo calculation.
bool WriteBlock(const uint32_t height, const uint256& blockHash);
uint256 ReadBlockHash(const uint32_t& height);

private:
AnchorIndexImpl anchors;
AnchorRec const * top = nullptr;
Expand Down Expand Up @@ -501,20 +505,6 @@ bool ContextualValidateAnchor(const CAnchorData& anchor, CBlockIndex &anchorBloc
// Get info from data embedded into CAnchorData::nextTeam
bool GetAnchorEmbeddedData(const CKeyID& data, uint64_t& anchorCreationHeight, std::shared_ptr<std::vector<unsigned char>>& prefix);

// Comparator to organise by Bitcoin height, anchor height or TX hash
const auto OrderPendingAnchors = [](const CAnchorIndex::AnchorRec& a, const CAnchorIndex::AnchorRec& b) {
if (a.btcHeight == b.btcHeight) {
if (a.anchor.height == b.anchor.height) {
return a.txHash < b.txHash;
}

// Higher DeFi height wins
return a.anchor.height > b.anchor.height;
}

return a.btcHeight < b.btcHeight;
};

// Selects "best" of two anchors at the equal btc height (prevs must be checked before)
CAnchorIndex::AnchorRec const* BestOfTwo(CAnchorIndex::AnchorRec const* a1, CAnchorIndex::AnchorRec const* a2);

Expand All @@ -523,4 +513,12 @@ extern std::unique_ptr<CAnchorAuthIndex> panchorauths;
extern std::unique_ptr<CAnchorIndex> panchors;
extern std::unique_ptr<CAnchorAwaitingConfirms> panchorAwaitingConfirms;

namespace spv
{
// Define comparator and set to hold pending anchors
using PendingOrderType = std::function<bool (const CAnchorIndex::AnchorRec&, const CAnchorIndex::AnchorRec&)>;
using PendingSet = std::set<CAnchorIndex::AnchorRec, PendingOrderType>;
extern const PendingOrderType PendingOrder;
}

#endif // DEFI_MASTERNODES_ANCHORS_H
16 changes: 8 additions & 8 deletions src/spv/bitcoin/BRPeerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ static void _requestUnrelayedTxGetdataDone(void *info, int success)
}
else if (! isPublishing && _BRTxPeerListCount(manager->txRelays, hash) < manager->maxConnectCount) {
// set timestamp 0 to mark as unverified
BRWalletUpdateTransactions(manager->wallet, &hash, 1, TX_UNCONFIRMED, 0);
BRWalletUpdateTransactions(manager->wallet, &hash, 1, TX_UNCONFIRMED, 0, UINT256_ZERO);
}
}
}
Expand Down Expand Up @@ -1053,7 +1053,7 @@ static void _peerRelayedTx(void *info, BRTransaction *tx)

// set timestamp when tx is verified
if (tx && relayCount >= manager->maxConnectCount && tx->blockHeight == TX_UNCONFIRMED && tx->timestamp == 0) {
BRWalletUpdateTransactions(manager->wallet, &tx->txHash, 1, TX_UNCONFIRMED, (uint32_t)time(NULL));
BRWalletUpdateTransactions(manager->wallet, &tx->txHash, 1, TX_UNCONFIRMED, (uint32_t)time(NULL), UINT256_ZERO);
}

manager->lock.unlock();
Expand Down Expand Up @@ -1107,7 +1107,7 @@ static void _peerHasTx(void *info, UInt256 txHash)

// set timestamp when tx is verified
if (relayCount >= manager->maxConnectCount && tx && tx->blockHeight == TX_UNCONFIRMED && tx->timestamp == 0) {
BRWalletUpdateTransactions(manager->wallet, &txHash, 1, TX_UNCONFIRMED, (uint32_t)time(NULL));
BRWalletUpdateTransactions(manager->wallet, &txHash, 1, TX_UNCONFIRMED, (uint32_t)time(NULL), UINT256_ZERO);
}

_BRTxPeerListRemovePeer(manager->txRequests, txHash, peer);
Expand All @@ -1134,7 +1134,7 @@ static void _peerRejectedTx(void *info, UInt256 txHash, uint8_t code)
if (tx) {
if (_BRTxPeerListRemovePeer(manager->txRelays, txHash, peer) && tx->blockHeight == TX_UNCONFIRMED) {
// set timestamp 0 to mark tx as unverified
BRWalletUpdateTransactions(manager->wallet, &txHash, 1, TX_UNCONFIRMED, 0);
BRWalletUpdateTransactions(manager->wallet, &txHash, 1, TX_UNCONFIRMED, 0, UINT256_ZERO);
}

// if we get rejected for any reason other than double-spend, the peer is likely misconfigured
Expand Down Expand Up @@ -1305,7 +1305,7 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block)

BRSetAdd(manager->blocks, block);
manager->lastBlock = block;
if (txCount > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, txCount, block->height, txTime);
if (txCount > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, txCount, block->height, txTime, block->blockHash);
if (manager->downloadPeer) BRPeerSetCurrentBlockHeight(manager->downloadPeer, block->height);

if (block->height < manager->estimatedHeight && peer == manager->downloadPeer) {
Expand All @@ -1332,7 +1332,7 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block)

assert (NULL != b);
if (BRMerkleBlockEq(b, block)) { // if it's not on a fork, set block heights for its transactions
if (txCount > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, txCount, block->height, txTime);
if (txCount > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, txCount, block->height, txTime, block->blockHash);
if (block->height == manager->lastBlock->height) manager->lastBlock = block;
}

Expand Down Expand Up @@ -1374,7 +1374,7 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block)
assert (NULL != block);
peer_log(peer, "reorganizing chain from height %" PRIu32 ", new height is %" PRIu32, b->height, block->height);

BRWalletSetTxUnconfirmedAfter(manager->wallet, b->height); // mark tx after the join point as unconfirmed
BRWalletSetTxUnconfirmedAfter(manager->wallet, b->height, b->blockHash); // mark tx after the join point as unconfirmed

b = block;

Expand All @@ -1392,7 +1392,7 @@ static void _peerRelayedBlock(void *info, BRMerkleBlock *block)
count = BRMerkleBlockTxHashes(b, txHashes, count);
b = (BRMerkleBlock *)BRSetGet(manager->blocks, &b->prevBlock);
if (b) timestamp = timestamp/2 + b->timestamp/2;
if (count > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, count, height, timestamp);
if (count > 0) BRWalletUpdateTransactions(manager->wallet, txHashes, count, height, timestamp, b->blockHash);
}

manager->lastBlock = block;
Expand Down
14 changes: 7 additions & 7 deletions src/spv/bitcoin/BRWallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct BRWalletStruct {
void *callbackInfo;
void (*balanceChanged)(void *info, uint64_t balance);
void (*txAdded)(void *info, BRTransaction *tx);
void (*txUpdated)(void *info, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight, uint32_t timestamp);
void (*txUpdated)(void *info, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight, uint32_t timestamp, const UInt256& blockHash);
void (*txDeleted)(void *info, UInt256 txHash, int notifyUser, int recommendRescan);
boost::mutex lock;
};
Expand Down Expand Up @@ -521,15 +521,15 @@ BRWallet *BRWalletNew(BRTransaction *transactions[], size_t txCount, BRMasterPub
// info is a void pointer that will be passed along with each callback call
// void balanceChanged(void *, uint64_t) - called when the wallet balance changes
// void txAdded(void *, BRTransaction *) - called when transaction is added to the wallet
// void txUpdated(void *, const UInt256[], size_t, uint32_t, uint32_t)
// void txUpdated(void *, const UInt256[], size_t, uint32_t, uint32_t, const UInt256&)
// - called when the blockHeight or timestamp of previously added transactions are updated
// void txDeleted(void *, UInt256) - called when a previously added transaction is removed from the wallet
// NOTE: if a transaction is deleted, and BRWalletAmountSentByTx() is greater than 0, recommend the user do a rescan
void BRWalletSetCallbacks(BRWallet *wallet, void *info,
void (*balanceChanged)(void *info, uint64_t balance),
void (*txAdded)(void *info, BRTransaction *tx),
void (*txUpdated)(void *info, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight,
uint32_t timestamp),
uint32_t timestamp, const UInt256& blockHash),
void (*txDeleted)(void *info, UInt256 txHash, int notifyUser, int recommendRescan))
{
assert(wallet != NULL);
Expand Down Expand Up @@ -1319,7 +1319,7 @@ int BRWalletTransactionIsVerified(BRWallet *wallet, const BRTransaction *tx)
// set the block heights and timestamps for the given transactions
// use height TX_UNCONFIRMED and timestamp 0 to indicate a tx should remain marked as unverified (not 0-conf safe)
void BRWalletUpdateTransactions(BRWallet *wallet, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight,
uint32_t timestamp)
uint32_t timestamp, const UInt256& blockHash)
{
BRTransaction *tx;
UInt256 hashes[txCount];
Expand Down Expand Up @@ -1356,11 +1356,11 @@ void BRWalletUpdateTransactions(BRWallet *wallet, const UInt256 txHashes[], size

if (needsUpdate) _BRWalletUpdateBalance(wallet);
wallet->lock.unlock();
if (j > 0 && wallet->txUpdated) wallet->txUpdated(wallet->callbackInfo, hashes, j, blockHeight, timestamp);
if (j > 0 && wallet->txUpdated) wallet->txUpdated(wallet->callbackInfo, hashes, j, blockHeight, timestamp, blockHash);
}

// marks all transactions confirmed after blockHeight as unconfirmed (useful for chain re-orgs)
void BRWalletSetTxUnconfirmedAfter(BRWallet *wallet, uint32_t blockHeight)
void BRWalletSetTxUnconfirmedAfter(BRWallet *wallet, uint32_t blockHeight, const UInt256& blockHash)
{
size_t i, j, count;

Expand All @@ -1380,7 +1380,7 @@ void BRWalletSetTxUnconfirmedAfter(BRWallet *wallet, uint32_t blockHeight)

if (count > 0) _BRWalletUpdateBalance(wallet);
wallet->lock.unlock();
if (count > 0 && wallet->txUpdated) wallet->txUpdated(wallet->callbackInfo, hashes, count, TX_UNCONFIRMED, 0);
if (count > 0 && wallet->txUpdated) wallet->txUpdated(wallet->callbackInfo, hashes, count, TX_UNCONFIRMED, 0, UINT256_ZERO);
}

// returns the amount received by the wallet from the transaction (total outputs to change and/or receive addresses)
Expand Down
8 changes: 4 additions & 4 deletions src/spv/bitcoin/BRWallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ BRWallet *BRWalletNew(BRTransaction *transactions[], size_t txCount, BRMasterPub
// info is a void pointer that will be passed along with each callback call
// void balanceChanged(void *, uint64_t) - called when the wallet balance changes
// void txAdded(void *, BRTransaction *) - called when transaction is added to the wallet
// void txUpdated(void *, const UInt256[], size_t, uint32_t, uint32_t)
// void txUpdated(void *, const UInt256[], size_t, uint32_t, uint32_t, const UInt256&)
// - called when the blockHeight or timestamp of previously added transactions are updated
// void txDeleted(void *, UInt256, int, int) - called when a previously added transaction is removed from the wallet
void BRWalletSetCallbacks(BRWallet *wallet, void *info,
void (*balanceChanged)(void *info, uint64_t balance),
void (*txAdded)(void *info, BRTransaction *tx),
void (*txUpdated)(void *info, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight,
uint32_t timestamp),
uint32_t timestamp, const UInt256& blockHash),
void (*txDeleted)(void *info, UInt256 txHash, int notifyUser, int recommendRescan));

// wallets are composed of chains of addresses
Expand Down Expand Up @@ -182,10 +182,10 @@ int BRWalletTransactionIsVerified(BRWallet *wallet, const BRTransaction *tx);
// set the block heights and timestamps for the given transactions
// use height TX_UNCONFIRMED and timestamp 0 to indicate a tx should remain marked as unverified (not 0-conf safe)
void BRWalletUpdateTransactions(BRWallet *wallet, const UInt256 txHashes[], size_t txCount, uint32_t blockHeight,
uint32_t timestamp);
uint32_t timestamp, const UInt256 &blockHash);

// marks all transactions confirmed after blockHeight as unconfirmed (useful for chain re-orgs)
void BRWalletSetTxUnconfirmedAfter(BRWallet *wallet, uint32_t blockHeight);
void BRWalletSetTxUnconfirmedAfter(BRWallet *wallet, uint32_t blockHeight, const UInt256& blockHash);

// returns the amount received by the wallet from the transaction (total outputs to change and/or receive addresses)
uint64_t BRWalletAmountReceivedFromTx(BRWallet *wallet, const BRTransaction *tx);
Expand Down
Loading

0 comments on commit 8e9d93e

Please sign in to comment.