From 967443acc6a73e9d0537ae1ccc877d8de7adfb67 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 29 Sep 2022 19:25:05 +0700 Subject: [PATCH 01/37] feat: add implementation of DIP 0027 Credit Asset Locks This commit includes: - Asset Lock transaction - Asset Unlock transaction (withdrawal) - Unit tests for Asset Lock/Unlock tx - Credit Pool in coinbase and its serialization in evo db when it required - New functional test `feature_asset_locks.py` - RPC for Credit Pool (currently locked amount) - check validity of asset-locked amount in coin base tx for new block Asset unlock transaction requires a lot of validation that implemented: - Asset unlock limits are equals to: min(max(100, min(.10 * assetlockpool, 1000)), assetlockpool) - Asset unlock transaction are restricted to be accepted during only 48 blocks - Removing expired asset-unlock transaction from mempool - An index validation for asset-unlock txes - Indexes also validated before beeing added to txmempool - Unlock transactions are validated twice: when accepting to block chain and in miner All of these checks have functional tests for that, and also: - Rollback of block with tx Asset Lock - Rollback of block with tx Asset Unlock - Duplicate 'asset unlock' tx for new block - Asset unlock rollback and reconsider - Reconsider/invalidate blocks - Manually created block with invalid transaction --- src/Makefile.am | 4 + src/Makefile.test.include | 1 + src/bloom.cpp | 4 + src/chainparams.cpp | 4 + src/consensus/params.h | 1 + src/consensus/tx_check.cpp | 13 +- src/consensus/tx_verify.cpp | 15 + src/core_write.cpp | 15 + src/evo/assetlocktx.cpp | 237 +++++++++ src/evo/assetlocktx.h | 144 ++++++ src/evo/cbtx.cpp | 13 +- src/evo/cbtx.h | 7 + src/evo/creditpool.cpp | 335 ++++++++++++ src/evo/creditpool.h | 175 +++++++ src/evo/specialtxman.cpp | 45 +- src/evo/specialtxman.h | 10 +- src/init.cpp | 3 + src/merkleblock.cpp | 2 + src/miner.cpp | 39 +- src/miner.h | 3 +- src/node/context.cpp | 1 + src/node/context.h | 2 + src/primitives/transaction.h | 2 + src/rpc/evo.cpp | 5 +- src/test/evo_assetlocks_tests.cpp | 360 +++++++++++++ src/test/util/setup_common.cpp | 5 + src/txmempool.cpp | 27 + src/txmempool.h | 2 + src/validation.cpp | 14 +- test/functional/feature_asset_locks.py | 505 +++++++++++++++++++ test/functional/feature_nulldummy.py | 5 +- test/functional/test_framework/blocktools.py | 5 +- test/functional/test_framework/messages.py | 91 +++- test/functional/test_runner.py | 1 + test/lint/lint-circular-dependencies.sh | 5 + 35 files changed, 2066 insertions(+), 34 deletions(-) create mode 100644 src/evo/assetlocktx.cpp create mode 100644 src/evo/assetlocktx.h create mode 100644 src/evo/creditpool.cpp create mode 100644 src/evo/creditpool.h create mode 100644 src/test/evo_assetlocks_tests.cpp create mode 100755 test/functional/feature_asset_locks.py diff --git a/src/Makefile.am b/src/Makefile.am index edbf2936b0f38..2bb600f89ef90 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -169,8 +169,10 @@ BITCOIN_CORE_H = \ cuckoocache.h \ ctpl_stl.h \ cxxtimer.hpp \ + evo/assetlocktx.h \ evo/dmn_types.h \ evo/cbtx.h \ + evo/creditpool.h \ evo/deterministicmns.h \ evo/dmnstate.h \ evo/evodb.h \ @@ -384,7 +386,9 @@ libbitcoin_server_a_SOURCES = \ consensus/tx_verify.cpp \ dbwrapper.cpp \ dsnotificationinterface.cpp \ + evo/assetlocktx.cpp \ evo/cbtx.cpp \ + evo/creditpool.cpp \ evo/deterministicmns.cpp \ evo/dmnstate.cpp \ evo/evodb.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 7152329f7acc3..c48eacf1c057c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -95,6 +95,7 @@ BITCOIN_TESTS =\ test/dip0020opcodes_tests.cpp \ test/descriptor_tests.cpp \ test/dynamic_activation_thresholds_tests.cpp \ + test/evo_assetlocks_tests.cpp \ test/evo_deterministicmns_tests.cpp \ test/evo_instantsend_tests.cpp \ test/evo_simplifiedmns_tests.cpp \ diff --git a/src/bloom.cpp b/src/bloom.cpp index d8c2e6dac50cb..2c30ce4aaee1c 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -194,6 +194,10 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t case(TRANSACTION_MNHF_SIGNAL): // No additional checks for this transaction types return false; + case(TRANSACTION_ASSET_LOCK): + case(TRANSACTION_ASSET_UNLOCK): + // TODO asset lock/unlock bloom? + return false; } LogPrintf("Unknown special transaction type in Bloom filter check.\n"); diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7e4e42e610bcd..aba5d97ed992a 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -258,6 +258,7 @@ class CMainParams : public CChainParams { consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_400_85; + consensus.llmqTypeAssetLocks = Consensus::LLMQType::LLMQ_400_85; fDefaultConsistencyChecks = false; fRequireStandard = true; @@ -447,6 +448,7 @@ class CTestNetParams : public CChainParams { consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_25_67; consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60; + consensus.llmqTypeAssetLocks = Consensus::LLMQType::LLMQ_50_60; fDefaultConsistencyChecks = false; fRequireStandard = false; @@ -619,6 +621,7 @@ class CDevNetParams : public CChainParams { consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60; + consensus.llmqTypeAssetLocks = Consensus::LLMQType::LLMQ_50_60; UpdateDevnetLLMQChainLocksFromArgs(args); UpdateDevnetLLMQInstantSendFromArgs(args); @@ -891,6 +894,7 @@ class CRegTestParams : public CChainParams { consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_TEST_DIP0024; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_TEST_PLATFORM; consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_TEST; + consensus.llmqTypeAssetLocks = Consensus::LLMQType::LLMQ_TEST; UpdateLLMQTestParametersFromArgs(args, Consensus::LLMQType::LLMQ_TEST); UpdateLLMQTestParametersFromArgs(args, Consensus::LLMQType::LLMQ_TEST_INSTANTSEND); diff --git a/src/consensus/params.h b/src/consensus/params.h index 7072e441c4828..0c9083086d2c0 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -125,6 +125,7 @@ struct Params { LLMQType llmqTypeDIP0024InstantSend{LLMQType::LLMQ_NONE}; LLMQType llmqTypePlatform{LLMQType::LLMQ_NONE}; LLMQType llmqTypeMnhf{LLMQType::LLMQ_NONE}; + LLMQType llmqTypeAssetLocks{LLMQType::LLMQ_NONE}; }; } // namespace Consensus diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index dff067b685a4c..5c54c4e4242a9 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -12,15 +12,20 @@ bool CheckTransaction(const CTransaction& tx, TxValidationState& state) { - bool allowEmptyTxInOut = false; + bool allowEmptyTxIn = false; + bool allowEmptyTxOut = false; if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { - allowEmptyTxInOut = true; + allowEmptyTxIn = true; + allowEmptyTxOut = true; + } + if (tx.nType == TRANSACTION_ASSET_UNLOCK) { + allowEmptyTxIn = true; } // Basic checks that don't depend on any context - if (!allowEmptyTxInOut && tx.vin.empty()) + if (!allowEmptyTxIn && tx.vin.empty()) return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vin-empty"); - if (!allowEmptyTxInOut && tx.vout.empty()) + if (!allowEmptyTxOut && tx.vout.empty()) return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty"); // Size limits if (::GetSerializeSize(tx, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE) diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 58f1b2fc0bd3f..01c8a400e51e4 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -8,6 +8,7 @@ #include #include