mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Merge cc7aee39b9 into merged_master (Elements PR #1492)
This commit is contained in:
commit
43e88ba24e
10 changed files with 91 additions and 11 deletions
|
|
@ -52,6 +52,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman)
|
|||
argsman.AddArg("-total_valid_epochs", "Per-chain parameter that sets how long a particular fedpegscript is in effect for.", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
|
||||
argsman.AddArg("-evbparams=deployment:start:end:period:threshold", "Use given start/end times for specified version bits deployment (regtest or custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::ELEMENTS);
|
||||
argsman.AddArg("-con_start_p2wsh_script", "Create p2wsh addresses when starting in dynafed mode (regtest or custom only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::ELEMENTS);
|
||||
argsman.AddArg("-acceptunlimitedissuances", "Allow unblinded issuance amounts to exceed 21 million units", ArgsManager::ALLOW_ANY, OptionsCategory::ELEMENTS);
|
||||
// END ELEMENTS
|
||||
//
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
#include <chainparams.h>
|
||||
#include <confidential_validation.h>
|
||||
#include <issuance.h>
|
||||
#include <pegins.h>
|
||||
|
|
@ -103,14 +104,13 @@ static bool VerifyIssuanceAmount(secp256k1_pedersen_commitment& value_commit, se
|
|||
|
||||
// Build value commitment
|
||||
if (value.IsExplicit()) {
|
||||
if (!MoneyRange(value.GetAmount()) || value.GetAmount() == 0) {
|
||||
if ((asset == Params().GetConsensus().pegged_asset && !MoneyRange(value.GetAmount())) || value.GetAmount() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (!rangeproof.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ret = secp256k1_pedersen_commit(secp256k1_ctx_verify_amounts, &value_commit, explicit_blinds, value.GetAmount(), &asset_gen);
|
||||
// The explicit_blinds are all 0, and the amount is not 0. So secp256k1_pedersen_commit does not fail.
|
||||
assert(ret == 1);
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ public:
|
|||
consensus.subsidy_asset = CAsset();
|
||||
anyonecanspend_aremine = false;
|
||||
enforce_pak = false;
|
||||
accept_unlimited_issuances = false;
|
||||
multi_data_permitted = false;
|
||||
accept_discount_ct = false;
|
||||
create_discount_ct = false;
|
||||
|
|
@ -385,6 +386,7 @@ public:
|
|||
consensus.subsidy_asset = CAsset();
|
||||
anyonecanspend_aremine = false;
|
||||
enforce_pak = false;
|
||||
accept_unlimited_issuances = false;
|
||||
multi_data_permitted = false;
|
||||
accept_discount_ct = false;
|
||||
create_discount_ct = false;
|
||||
|
|
@ -547,6 +549,7 @@ public:
|
|||
consensus.subsidy_asset = CAsset();
|
||||
anyonecanspend_aremine = false;
|
||||
enforce_pak = false;
|
||||
accept_unlimited_issuances = false;
|
||||
multi_data_permitted = false;
|
||||
accept_discount_ct = false;
|
||||
create_discount_ct = false;
|
||||
|
|
@ -658,6 +661,7 @@ public:
|
|||
consensus.subsidy_asset = CAsset();
|
||||
anyonecanspend_aremine = false;
|
||||
enforce_pak = false;
|
||||
accept_unlimited_issuances = false;
|
||||
multi_data_permitted = false;
|
||||
accept_discount_ct = false;
|
||||
create_discount_ct = false;
|
||||
|
|
@ -949,6 +953,8 @@ protected:
|
|||
|
||||
enforce_pak = args.GetBoolArg("-enforce_pak", false);
|
||||
|
||||
accept_unlimited_issuances = args.GetBoolArg("-acceptunlimitedissuances", false);
|
||||
|
||||
// Allow multiple op_return outputs by relay policy
|
||||
multi_data_permitted = args.GetBoolArg("-multi_data_permitted", enforce_pak);
|
||||
|
||||
|
|
@ -1204,6 +1210,8 @@ public:
|
|||
|
||||
enforce_pak = true;
|
||||
|
||||
accept_unlimited_issuances = false;
|
||||
|
||||
multi_data_permitted = true;
|
||||
create_discount_ct = args.GetBoolArg("-creatediscountct", false);
|
||||
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", true) || create_discount_ct;
|
||||
|
|
@ -1557,6 +1565,8 @@ public:
|
|||
|
||||
enforce_pak = args.GetBoolArg("-enforce_pak", enforce_pak);
|
||||
|
||||
accept_unlimited_issuances = false;
|
||||
|
||||
multi_data_permitted = args.GetBoolArg("-multi_data_permitted", multi_data_permitted);
|
||||
create_discount_ct = args.GetBoolArg("-creatediscountct", create_discount_ct);
|
||||
accept_discount_ct = args.GetBoolArg("-acceptdiscountct", accept_discount_ct) || create_discount_ct;
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ public:
|
|||
const std::string& ParentBech32HRP() const { return parent_bech32_hrp; }
|
||||
const std::string& ParentBlech32HRP() const { return parent_blech32_hrp; }
|
||||
bool GetEnforcePak() const { return enforce_pak; }
|
||||
bool GetAcceptUnlimitedIssuances() const { return accept_unlimited_issuances; }
|
||||
bool GetMultiDataPermitted() const { return multi_data_permitted; }
|
||||
bool GetAcceptDiscountCT() const { return accept_discount_ct; }
|
||||
bool GetCreateDiscountCT() const { return create_discount_ct; }
|
||||
|
|
@ -209,6 +210,7 @@ protected:
|
|||
std::string parent_bech32_hrp;
|
||||
std::string parent_blech32_hrp;
|
||||
bool enforce_pak;
|
||||
bool accept_unlimited_issuances;
|
||||
bool multi_data_permitted;
|
||||
bool accept_discount_ct;
|
||||
bool create_discount_ct;
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
|
|||
bool is_bech32_hrp = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP());
|
||||
bool is_blech32_hrp = (ToLower(str.substr(0, params.Blech32HRP().size())) == params.Blech32HRP());
|
||||
|
||||
if (!is_bech32 && !is_blech32 && !is_bech32_hrp && !is_blech32_hrp && DecodeBase58Check(str, data, 55)) {
|
||||
if (!is_bech32 && !is_blech32 && !is_bech32_hrp && !is_blech32_hrp && DecodeBase58Check(str, data, 55)) {
|
||||
// base58-encoded Bitcoin addresses.
|
||||
// Public-key-hash-addresses have version 0 (or 111 testnet).
|
||||
// The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
|
||||
|
|
|
|||
|
|
@ -321,6 +321,20 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IsIssuanceInMoneyRange(const CTransaction& tx)
|
||||
{
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i) {
|
||||
const CAssetIssuance& issuance = tx.vin[i].assetIssuance;
|
||||
if (issuance.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
if (issuance.nAmount.IsExplicit() && !MoneyRange(issuance.nAmount.GetAmount())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
|
||||
{
|
||||
return (std::max(nWeight, nSigOpCost * bytes_per_sigop) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,9 @@ static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQ
|
|||
// ELEMENTS: keep a copy of the upstream default dust relay fee rate
|
||||
static const unsigned int DUST_RELAY_TX_FEE_BITCOIN = 3000;
|
||||
|
||||
// ELEMENTS: allow unblinded issuances/reissuances greater than MAX_MONEY
|
||||
static const bool DEFAULT_ACCEPT_UNLIMITED_ISSUANCES = true;
|
||||
|
||||
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||
|
||||
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||
|
|
@ -161,6 +164,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
*/
|
||||
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||
|
||||
/* ELEMENTS
|
||||
* Check if unblinded issuance/reissuance is in MoneyRange
|
||||
*/
|
||||
bool IsIssuanceInMoneyRange(const CTransaction& tx);
|
||||
|
||||
/** Compute the virtual transaction size (weight reinterpreted as bytes). */
|
||||
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop);
|
||||
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost, unsigned int bytes_per_sigop);
|
||||
|
|
|
|||
|
|
@ -750,6 +750,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
}
|
||||
}
|
||||
|
||||
// Check unblinded issuance is in MoneyRange if configured
|
||||
if (!chainparams.GetAcceptUnlimitedIssuances() && !IsIssuanceInMoneyRange(tx)) {
|
||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "issuance-out-of-range", "Issuance is greater than 21 million and acceptunlimitedissuances is not enabled.");
|
||||
}
|
||||
|
||||
// Transactions smaller than 65 non-witness bytes are not relayed to mitigate CVE-2017-12842.
|
||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE)
|
||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small");
|
||||
|
|
@ -2378,12 +2383,12 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
|||
|
||||
num_blocks_total++;
|
||||
|
||||
// Check that all non-zero coinbase outputs pay to the required destination
|
||||
// Check that all non-zero policyAsset coinbase outputs pay to the required destination
|
||||
const CScript& mandatory_coinbase_destination = params.GetConsensus().mandatory_coinbase_destination;
|
||||
if (mandatory_coinbase_destination != CScript()) {
|
||||
for (auto& txout : block.vtx[0]->vout) {
|
||||
bool mustPay = !txout.nValue.IsExplicit() || txout.nValue.GetAmount() != 0;
|
||||
if (mustPay && txout.scriptPubKey != mandatory_coinbase_destination) {
|
||||
if (mustPay && txout.nAsset.GetAsset() == policyAsset && txout.scriptPubKey != mandatory_coinbase_destination) {
|
||||
LogPrintf("ERROR: ConnectBlock(): Coinbase outputs didn't match required scriptPubKey\n");
|
||||
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-coinbase-txos");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ BECH32_INVALID_PREFIX = 'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3z
|
|||
BECH32_TOO_LONG = 'ert1q049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23mpsg3jcedq9xv049edschfnwystcqnsvyfpj23m'
|
||||
BECH32_ONE_ERROR = 'ert1qtmp7aayg7p24uslctssvjm06q5phz4yr7gdkdv'
|
||||
BECH32_ONE_ERROR_CAPITALS = 'ERT1QTMP7AAYG7P24USLCTSSVJM06Q5PHZ4YR7GDKDV'
|
||||
BECH32_TWO_ERRORS = 'ert1qtmp74syg7p24uslctsavjm06q5phz4yr7gdkdv' # should be bcrt1qax9suht3qv95sw33wavx8crpxduefdrsvgsklx
|
||||
BECH32_TWO_ERRORS = 'ert1qtmp74syg7p24uslctsavjm06q5phz4yr7gdkdv'
|
||||
BECH32_NO_SEPARATOR = 'ertq049ldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
||||
BECH32_INVALID_CHAR = 'ert1q04oldschfnwystcqnsvyfpj23mpsg3jcedq9xv'
|
||||
BECH32_MULTISIG_TWO_ERRORS = 'ert1qmzm84udpua6axdstxlpwafca7g7na5w2yu8c7vqhe0rhjkcrfcfqwymvhe'
|
||||
|
|
@ -32,7 +32,7 @@ BECH32_WRONG_VERSION = 'ert1ptmp74ayg7p24uslctssvjm06q5phz4yr7gdkdv'
|
|||
|
||||
BASE58_VALID = '2dcjQH4DQC3pMcSQkMkSQyPPEr7rZ6Ga4GR'
|
||||
BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
|
||||
BASE58_INVALID_CHECKSUM = '2NEPDEyVRWtPzPL38jaQZkWvbK8E6ywvB6d'
|
||||
BASE58_INVALID_CHECKSUM = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJJfn'
|
||||
BASE58_INVALID_LENGTH = '2dcjQH4DQC3pMcSQkMkSQyPPEr7rZ6Ga4GR7rZ6Ga4GR'
|
||||
|
||||
INVALID_ADDRESS = 'asfah14i8fajz0123f'
|
||||
|
|
@ -73,12 +73,12 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework):
|
|||
|
||||
def test_validateaddress(self):
|
||||
# Invalid Bech32
|
||||
self.check_invalid(BECH32_INVALID_SIZE, "Invalid Bech32 address program size (41 bytes)")
|
||||
self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported prefix for Segwit (Bech32) address (expected ert, got bc).') # ELEMENTS
|
||||
self.check_invalid(BECH32_INVALID_SIZE, 'Invalid Bech32 address program size (41 bytes)')
|
||||
self.check_invalid(BECH32_INVALID_PREFIX, 'Invalid or unsupported prefix for Segwit (Bech32) address (expected ert, got bc).')
|
||||
self.check_invalid(BECH32_INVALID_BECH32, 'Version 1+ witness address must use Bech32m checksum')
|
||||
self.check_invalid(BECH32_INVALID_BECH32M, 'Version 0 witness address must use Bech32 checksum')
|
||||
self.check_invalid(BECH32_INVALID_VERSION, 'Invalid Bech32 address witness version')
|
||||
self.check_invalid(BECH32_INVALID_V0_SIZE, "Invalid Bech32 v0 address program size (21 bytes), per BIP141")
|
||||
self.check_invalid(BECH32_INVALID_V0_SIZE, 'Invalid Bech32 v0 address program size (21 bytes), per BIP141')
|
||||
self.check_invalid(BECH32_TOO_LONG, 'Bech32 string too long', list(range(90, 107)))
|
||||
self.check_invalid(BECH32_ONE_ERROR, 'Invalid Bech32 checksum', [9])
|
||||
self.check_invalid(BECH32_TWO_ERRORS, 'Invalid Bech32 checksum', [10, 23])
|
||||
|
|
|
|||
|
|
@ -7,13 +7,21 @@ from test_framework.blocktools import COINBASE_MATURITY
|
|||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
|
||||
class WalletTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 3
|
||||
self.extra_args = [['-blindedaddresses=1']] * self.num_nodes
|
||||
args = [
|
||||
"-blindedaddresses=1"
|
||||
]
|
||||
self.extra_args = [
|
||||
args + ["-acceptunlimitedissuances=1"],
|
||||
args + ["-acceptunlimitedissuances=1"],
|
||||
args, # node 2 blocks unblinded issuances out of moneyrange
|
||||
]
|
||||
|
||||
def add_options(self, parser):
|
||||
self.add_wallet_options(parser)
|
||||
|
|
@ -38,6 +46,17 @@ class WalletTest(BitcoinTestFramework):
|
|||
self.generate(self.nodes[0], 1)
|
||||
assert_equal(self.nodes[0].getbalance()[asset], 200_000_000)
|
||||
|
||||
self.log.info("Issue more than 21 million of a unblinded non-policy asset")
|
||||
issuance = self.nodes[0].issueasset(300_000_000, 100, False)
|
||||
unblinded_asset = issuance['asset']
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert_equal(self.nodes[0].getbalance()[unblinded_asset], 300_000_000)
|
||||
|
||||
self.log.info("Reissue more than 21 million of a unblinded non-policy asset")
|
||||
self.nodes[0].reissueasset(unblinded_asset, 200_000_000)
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert_equal(self.nodes[0].getbalance()[unblinded_asset], 500_000_000)
|
||||
|
||||
# send more than 21 million of that asset
|
||||
addr = self.nodes[1].getnewaddress()
|
||||
self.nodes[0].sendtoaddress(address=addr, amount=22_000_000, assetlabel=asset)
|
||||
|
|
@ -86,5 +105,26 @@ class WalletTest(BitcoinTestFramework):
|
|||
self.nodes[2].loadwallet(self.default_wallet_name)
|
||||
assert_equal(self.nodes[2].getbalance()[asset], 200_000_000)
|
||||
|
||||
# send some policy asset to node 2 for fees
|
||||
addr = self.nodes[2].getnewaddress()
|
||||
self.nodes[0].sendtoaddress(address=addr, amount=1)
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert_equal(self.nodes[2].getbalance()['bitcoin'], 1)
|
||||
|
||||
self.log.info("Issue more than 21 million of a non-policy asset on node 2 - rejected from mempool")
|
||||
issuance = self.nodes[2].issueasset(300_000_000, 100, False)
|
||||
asset = issuance['asset']
|
||||
issuance_tx = self.nodes[2].gettransaction(issuance["txid"])
|
||||
assert_raises_rpc_error(-26, "issuance-out-of-range", self.nodes[2].sendrawtransaction, issuance_tx['hex'])
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert(asset not in self.nodes[2].getbalance())
|
||||
# transaction should be accepted on node 0
|
||||
self.nodes[0].sendrawtransaction(issuance_tx["hex"])
|
||||
assert(issuance['txid'] in self.nodes[0].getrawmempool())
|
||||
assert(issuance['txid'] not in self.nodes[2].getrawmempool())
|
||||
self.generate(self.nodes[0], 1)
|
||||
assert(asset not in self.nodes[0].getbalance())
|
||||
assert_equal(self.nodes[2].getbalance()[asset], 300_000_000)
|
||||
|
||||
if __name__ == '__main__':
|
||||
WalletTest().main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue