mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-15 12:51:00 +02:00
[BROKEN] Introduce CA in data structures
This commit is contained in:
parent
04d06917d2
commit
d53479c9ff
17 changed files with 336 additions and 135 deletions
|
|
@ -48,10 +48,8 @@ static CBlock CreateGenesisBlock(const Consensus::Params& params, const CScript&
|
|||
CMutableTransaction txNew;
|
||||
txNew.nVersion = 1;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vout.resize(1);
|
||||
txNew.vin[0].scriptSig = genesisScriptSig;
|
||||
txNew.vout[0].nValue = genesisReward;
|
||||
txNew.vout[0].scriptPubKey = genesisOutputScript;
|
||||
txNew.vout.push_back(CTxOut(CAsset(), genesisReward, genesisOutputScript));
|
||||
|
||||
CBlock genesis;
|
||||
genesis.nTime = nTime;
|
||||
|
|
@ -86,23 +84,6 @@ static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits
|
|||
return CreateGenesisBlock(params, genesisScriptSig, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
|
||||
}
|
||||
|
||||
/** Add an issuance transaction to the genesis block. Typically used to pre-issue
|
||||
* the policyAsset of a blockchain. The genesis block is not actually validated,
|
||||
* so this transaction simply has to match issuance structure. */
|
||||
static void AppendInitialIssuance(CBlock& genesis_block, const COutPoint& prevout, const int64_t asset_values, const CScript& issuance_destination) {
|
||||
|
||||
// Note: Genesis block isn't actually validated, outputs are entered into utxo db only
|
||||
CMutableTransaction txNew;
|
||||
txNew.nVersion = 1;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vin[0].prevout = prevout;
|
||||
|
||||
txNew.vout.push_back(CTxOut(asset_values, issuance_destination));
|
||||
|
||||
genesis_block.vtx.push_back(MakeTransactionRef(std::move(txNew)));
|
||||
genesis_block.hashMerkleRoot = BlockMerkleRoot(genesis_block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main network
|
||||
*/
|
||||
|
|
@ -623,8 +604,8 @@ class CCustomParams : public CRegTestParams {
|
|||
// Intended compatibility with Liquid v1 and elements-0.14.1
|
||||
std::vector<unsigned char> commit = CommitToArguments(consensus, strNetworkID);
|
||||
genesis = CreateGenesisBlock(consensus, CScript(commit), CScript(OP_RETURN), 1296688602, 2, 0x207fffff, 1, 0);
|
||||
if (initialFreeCoins != 0) {
|
||||
AppendInitialIssuance(genesis, COutPoint(uint256(commit), 0), initialFreeCoins, CScript() << OP_TRUE);
|
||||
if (initialFreeCoins != 0 || initial_reissuance_tokens != 0) {
|
||||
AppendInitialIssuance(genesis, COutPoint(uint256(commit), 0), parentGenesisBlockHash, (initialFreeCoins > 0) ? 1 : 0, initialFreeCoins, (initial_reissuance_tokens > 0) ? 1 : 0, initial_reissuance_tokens, CScript() << OP_TRUE);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error(strprintf("Invalid -genesis_style (%s)", consensus.genesis_style));
|
||||
|
|
|
|||
|
|
@ -124,7 +124,16 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static const Coin coinEmpty;
|
||||
// ELEMENTS:
|
||||
// Because g_con_elementsmode is only set after the moment coinEmpty is initialized,
|
||||
// we have to force set it to an empty coin without the default asset commitment.
|
||||
Coin generateEmptyCoin() {
|
||||
Coin coin;
|
||||
coin.out.nValue.vchCommitment.clear();
|
||||
coin.out.nAsset.vchCommitment.clear();
|
||||
return coin;
|
||||
}
|
||||
static const Coin coinEmpty = generateEmptyCoin();
|
||||
|
||||
const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
|
||||
CCoinsMap::const_iterator it = FetchCoin(outpoint);
|
||||
|
|
@ -306,7 +315,8 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
|
|||
|
||||
CAmount nResult = 0;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
nResult += AccessCoin(tx.vin[i].prevout).out.nValue;
|
||||
// ELEMENTS: this method is for tests only, just naively add amounts
|
||||
nResult += AccessCoin(tx.vin[i].prevout).out.nValue.GetAmount();
|
||||
|
||||
return nResult;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,14 +95,42 @@ public:
|
|||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
if (!ser_action.ForRead()) {
|
||||
uint64_t nVal = CompressAmount(txout.nValue);
|
||||
READWRITE(VARINT(nVal));
|
||||
if (g_con_elementsmode) {
|
||||
if (!ser_action.ForRead()) {
|
||||
if (txout.nValue.IsExplicit()) {
|
||||
uint8_t b = 0;
|
||||
READWRITE(b);
|
||||
uint64_t nVal = CompressAmount(txout.nValue.GetAmount());
|
||||
READWRITE(VARINT(nVal));
|
||||
} else {
|
||||
uint8_t b = 1;
|
||||
READWRITE(b);
|
||||
READWRITE(txout.nValue);
|
||||
}
|
||||
} else {
|
||||
uint8_t type = 0;
|
||||
READWRITE(type);
|
||||
if (type == 0) {
|
||||
uint64_t nVal = 0;
|
||||
READWRITE(VARINT(nVal));
|
||||
txout.nValue = DecompressAmount(nVal);
|
||||
} else {
|
||||
READWRITE(txout.nValue);
|
||||
}
|
||||
}
|
||||
READWRITE(txout.nAsset);
|
||||
} else {
|
||||
uint64_t nVal = 0;
|
||||
READWRITE(VARINT(nVal));
|
||||
txout.nValue = DecompressAmount(nVal);
|
||||
if (!ser_action.ForRead()) {
|
||||
assert(txout.nValue.IsExplicit());
|
||||
uint64_t nVal = CompressAmount(txout.nValue.GetAmount());
|
||||
READWRITE(VARINT(nVal));
|
||||
} else {
|
||||
uint64_t nVal = 0;
|
||||
READWRITE(VARINT(nVal));
|
||||
txout.nValue = DecompressAmount(nVal);
|
||||
}
|
||||
}
|
||||
|
||||
CScriptCompressor cscript(REF(txout.scriptPubKey));
|
||||
READWRITE(cscript);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,13 +77,17 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated)
|
|||
{
|
||||
std::vector<uint256> leaves;
|
||||
leaves.resize(block.vtx.size());
|
||||
leaves[0].SetNull(); // The witness hash of the coinbase is 0.
|
||||
for (size_t s = 1; s < block.vtx.size(); s++) {
|
||||
if (g_con_elementsmode) {
|
||||
if (g_con_elementsmode) {
|
||||
// Coinbase witness hash for inputs is just CTxInWitness().GetHash()
|
||||
for (size_t s = 0; s < block.vtx.size(); s++) {
|
||||
leaves[s] = block.vtx[s]->GetWitnessOnlyHash();
|
||||
} else {
|
||||
}
|
||||
return ComputeFastMerkleRoot(std::move(leaves));
|
||||
} else {
|
||||
leaves[0].SetNull(); // The witness hash of the coinbase is 0.
|
||||
for (size_t s = 1; s < block.vtx.size(); s++) {
|
||||
leaves[s] = block.vtx[s]->GetWitnessHash();
|
||||
}
|
||||
return ComputeMerkleRoot(std::move(leaves), mutated);
|
||||
}
|
||||
return ComputeMerkleRoot(std::move(leaves), mutated);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define BITCOIN_CORE_IO_H
|
||||
|
||||
#include <amount.h>
|
||||
#include <asset.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <issuance.h>
|
||||
#include <key_io.h>
|
||||
#include <script/script.h>
|
||||
#include <script/standard.h>
|
||||
|
|
@ -16,6 +17,32 @@
|
|||
#include <utilmoneystr.h>
|
||||
#include <utilstrencodings.h>
|
||||
|
||||
#include <secp256k1_rangeproof.h>
|
||||
|
||||
static secp256k1_context* secp256k1_blind_context = NULL;
|
||||
|
||||
class RPCRawTransaction_ECC_Init {
|
||||
public:
|
||||
RPCRawTransaction_ECC_Init() {
|
||||
assert(secp256k1_blind_context == NULL);
|
||||
|
||||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
assert(ctx != NULL);
|
||||
|
||||
secp256k1_blind_context = ctx;
|
||||
}
|
||||
|
||||
~RPCRawTransaction_ECC_Init() {
|
||||
secp256k1_context *ctx = secp256k1_blind_context;
|
||||
secp256k1_blind_context = NULL;
|
||||
|
||||
if (ctx) {
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
static RPCRawTransaction_ECC_Init ecc_init_on_load;
|
||||
|
||||
UniValue ValueFromAmount(const CAmount& amount)
|
||||
{
|
||||
bool sign = amount < 0;
|
||||
|
|
@ -223,29 +250,65 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
|
||||
o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
|
||||
in.pushKV("scriptSig", o);
|
||||
|
||||
if (tx.witness.vtxinwit.size() > i) {
|
||||
const CScriptWitness &scriptWitness = tx.witness.vtxinwit[i].scriptWitness;
|
||||
if (!scriptWitness.IsNull()) {
|
||||
UniValue txinwitness(UniValue::VARR);
|
||||
for (const auto &item : scriptWitness.stack) {
|
||||
txinwitness.push_back(HexStr(item.begin(), item.end()));
|
||||
}
|
||||
in.pushKV("txinwitness", txinwitness);
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENTS:
|
||||
in.pushKV("is_pegin", txin.m_is_pegin);
|
||||
if (tx.witness.vtxinwit.size() > i && !tx.witness.vtxinwit[i].m_pegin_witness.IsNull()) {
|
||||
UniValue pegin_witness(UniValue::VARR);
|
||||
for (const auto& item : tx.witness.vtxinwit[i].m_pegin_witness.stack) {
|
||||
pegin_witness.push_back(HexStr(item.begin(), item.end()));
|
||||
}
|
||||
in.pushKV("pegin_witness", pegin_witness);
|
||||
}
|
||||
}
|
||||
in.pushKV("sequence", (int64_t)txin.nSequence);
|
||||
|
||||
if (tx.witness.vtxinwit.size() > i) {
|
||||
const CScriptWitness &scriptWitness = tx.witness.vtxinwit[i].scriptWitness;
|
||||
if (!scriptWitness.IsNull()) {
|
||||
UniValue txinwitness(UniValue::VARR);
|
||||
for (const auto &item : scriptWitness.stack) {
|
||||
txinwitness.push_back(HexStr(item.begin(), item.end()));
|
||||
}
|
||||
in.pushKV("txinwitness", txinwitness);
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENTS:
|
||||
if (tx.witness.vtxinwit.size() > i && !tx.witness.vtxinwit[i].m_pegin_witness.IsNull()) {
|
||||
UniValue pegin_witness(UniValue::VARR);
|
||||
for (const auto& item : tx.witness.vtxinwit[i].m_pegin_witness.stack) {
|
||||
pegin_witness.push_back(HexStr(item.begin(), item.end()));
|
||||
}
|
||||
in.pushKV("pegin_witness", pegin_witness);
|
||||
}
|
||||
const CAssetIssuance& issuance = txin.assetIssuance;
|
||||
if (!issuance.IsNull()) {
|
||||
UniValue issue(UniValue::VOBJ);
|
||||
issue.pushKV("assetBlindingNonce", issuance.assetBlindingNonce.GetHex());
|
||||
CAsset asset;
|
||||
CAsset token;
|
||||
uint256 entropy;
|
||||
if (issuance.assetBlindingNonce.IsNull()) {
|
||||
GenerateAssetEntropy(entropy, txin.prevout, issuance.assetEntropy);
|
||||
issue.pushKV("assetEntropy", entropy.GetHex());
|
||||
CalculateAsset(asset, entropy);
|
||||
CalculateReissuanceToken(token, entropy, issuance.nAmount.IsCommitment());
|
||||
issue.pushKV("isreissuance", false);
|
||||
issue.pushKV("token", token.GetHex());
|
||||
}
|
||||
else {
|
||||
issue.pushKV("assetEntropy", issuance.assetEntropy.GetHex());
|
||||
issue.pushKV("isreissuance", true);
|
||||
CalculateAsset(asset, issuance.assetEntropy);
|
||||
}
|
||||
issue.pushKV("asset", asset.GetHex());
|
||||
|
||||
if (issuance.nAmount.IsExplicit()) {
|
||||
issue.pushKV("assetamount", ValueFromAmount(issuance.nAmount.GetAmount()));
|
||||
} else if (issuance.nAmount.IsCommitment()) {
|
||||
issue.pushKV("assetamountcommitment", HexStr(issuance.nAmount.vchCommitment));
|
||||
}
|
||||
if (issuance.nInflationKeys.IsExplicit()) {
|
||||
issue.pushKV("tokenamount", ValueFromAmount(issuance.nInflationKeys.GetAmount()));
|
||||
} else if (issuance.nInflationKeys.IsCommitment()) {
|
||||
issue.pushKV("tokenamountcommitment", HexStr(issuance.nInflationKeys.vchCommitment));
|
||||
}
|
||||
in.pushKV("issuance", issue);
|
||||
}
|
||||
// END ELEMENTS
|
||||
|
||||
vin.push_back(in);
|
||||
}
|
||||
entry.pushKV("vin", vin);
|
||||
|
|
@ -256,7 +319,37 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
|
|||
|
||||
UniValue out(UniValue::VOBJ);
|
||||
|
||||
out.pushKV("value", ValueFromAmount(txout.nValue));
|
||||
if (txout.nValue.IsExplicit()) {
|
||||
out.pushKV("value", ValueFromAmount(txout.nValue.GetAmount()));
|
||||
} else {
|
||||
int exp;
|
||||
int mantissa;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
const CTxOutWitness* ptxoutwit = tx.witness.vtxoutwit.size() <= i? NULL: &tx.witness.vtxoutwit[i];
|
||||
if (ptxoutwit && secp256k1_rangeproof_info(secp256k1_blind_context, &exp, &mantissa, &minv, &maxv, &ptxoutwit->vchRangeproof[0], ptxoutwit->vchRangeproof.size())) {
|
||||
if (exp == -1) {
|
||||
out.pushKV("value", ValueFromAmount((CAmount)minv));
|
||||
} else {
|
||||
out.pushKV("value-minimum", ValueFromAmount((CAmount)minv));
|
||||
out.pushKV("value-maximum", ValueFromAmount((CAmount)maxv));
|
||||
}
|
||||
out.pushKV("ct-exponent", exp);
|
||||
out.pushKV("ct-bits", mantissa);
|
||||
}
|
||||
out.pushKV("valuecommitment", txout.nValue.GetHex());
|
||||
}
|
||||
if (g_con_elementsmode) {
|
||||
if (txout.nAsset.IsExplicit()) {
|
||||
out.pushKV("asset", txout.nAsset.GetAsset().GetHex());
|
||||
} else {
|
||||
out.pushKV("assetcommitment", txout.nAsset.GetHex());
|
||||
}
|
||||
|
||||
out.pushKV("commitmentnonce", txout.nNonce.GetHex());
|
||||
CPubKey pubkey(txout.nNonce.vchCommitment);
|
||||
out.pushKV("commitmentnonce_fully_valid", pubkey.IsFullyValid());
|
||||
}
|
||||
out.pushKV("n", (int64_t)i);
|
||||
|
||||
UniValue o(UniValue::VOBJ);
|
||||
|
|
|
|||
|
|
@ -355,8 +355,8 @@ public:
|
|||
num_blocks = ::chainActive.Height();
|
||||
return true;
|
||||
}
|
||||
CAmount getBalance() override { return m_wallet.GetBalance(); }
|
||||
CAmount getAvailableBalance(const CCoinControl& coin_control) override
|
||||
CAmountMap getBalance() override { return m_wallet.GetBalance(); }
|
||||
CAmountMap getAvailableBalance(const CCoinControl& coin_control) override
|
||||
{
|
||||
return m_wallet.GetAvailableBalance(&coin_control);
|
||||
}
|
||||
|
|
@ -370,12 +370,12 @@ public:
|
|||
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||
return m_wallet.IsMine(txout);
|
||||
}
|
||||
CAmount getDebit(const CTxIn& txin, isminefilter filter) override
|
||||
CAmountMap getDebit(const CTxIn& txin, isminefilter filter) override
|
||||
{
|
||||
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||
return m_wallet.GetDebit(txin, filter);
|
||||
}
|
||||
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
|
||||
CAmountMap getCredit(const CTxOut& txout, isminefilter filter) override
|
||||
{
|
||||
LOCK2(::cs_main, m_wallet.cs_wallet);
|
||||
return m_wallet.GetCredit(txout, filter);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define BITCOIN_INTERFACES_WALLET_H
|
||||
|
||||
#include <amount.h> // For CAmount
|
||||
#include <asset.h> // For CAmountMap
|
||||
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
|
||||
#include <script/ismine.h> // For isminefilter, isminetype
|
||||
#include <script/standard.h> // For CTxDestination
|
||||
|
|
@ -196,10 +197,10 @@ public:
|
|||
virtual bool tryGetBalances(WalletBalances& balances, int& num_blocks) = 0;
|
||||
|
||||
//! Get balance.
|
||||
virtual CAmount getBalance() = 0;
|
||||
virtual CAmountMap getBalance() = 0;
|
||||
|
||||
//! Get available balance.
|
||||
virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0;
|
||||
virtual CAmountMap getAvailableBalance(const CCoinControl& coin_control) = 0;
|
||||
|
||||
//! Return whether transaction input belongs to wallet.
|
||||
virtual isminetype txinIsMine(const CTxIn& txin) = 0;
|
||||
|
|
@ -208,10 +209,10 @@ public:
|
|||
virtual isminetype txoutIsMine(const CTxOut& txout) = 0;
|
||||
|
||||
//! Return debit amount if transaction input belongs to wallet.
|
||||
virtual CAmount getDebit(const CTxIn& txin, isminefilter filter) = 0;
|
||||
virtual CAmountMap getDebit(const CTxIn& txin, isminefilter filter) = 0;
|
||||
|
||||
//! Return credit amount if transaction input belongs to wallet.
|
||||
virtual CAmount getCredit(const CTxOut& txout, isminefilter filter) = 0;
|
||||
virtual CAmountMap getCredit(const CTxOut& txout, isminefilter filter) = 0;
|
||||
|
||||
//! Return AvailableCoins + LockedCoins grouped by wallet address.
|
||||
//! (put change in one group with wallet address)
|
||||
|
|
@ -309,13 +310,13 @@ struct WalletAddress
|
|||
//! Collection of wallet balances.
|
||||
struct WalletBalances
|
||||
{
|
||||
CAmount balance = 0;
|
||||
CAmount unconfirmed_balance = 0;
|
||||
CAmount immature_balance = 0;
|
||||
CAmountMap balance = CAmountMap();
|
||||
CAmountMap unconfirmed_balance = CAmountMap();
|
||||
CAmountMap immature_balance = CAmountMap();
|
||||
bool have_watch_only = false;
|
||||
CAmount watch_only_balance = 0;
|
||||
CAmount unconfirmed_watch_only_balance = 0;
|
||||
CAmount immature_watch_only_balance = 0;
|
||||
CAmountMap watch_only_balance = CAmountMap();
|
||||
CAmountMap unconfirmed_watch_only_balance = CAmountMap();
|
||||
CAmountMap immature_watch_only_balance = CAmountMap();
|
||||
|
||||
bool balanceChanged(const WalletBalances& prev) const
|
||||
{
|
||||
|
|
@ -334,9 +335,9 @@ struct WalletTx
|
|||
std::vector<isminetype> txout_is_mine;
|
||||
std::vector<CTxDestination> txout_address;
|
||||
std::vector<isminetype> txout_address_is_mine;
|
||||
CAmount credit;
|
||||
CAmount debit;
|
||||
CAmount change;
|
||||
CAmountMap credit;
|
||||
CAmountMap debit;
|
||||
CAmountMap change;
|
||||
int64_t time;
|
||||
std::map<std::string, std::string> value_map;
|
||||
bool is_coinbase;
|
||||
|
|
|
|||
|
|
@ -46,3 +46,37 @@ void CalculateReissuanceToken(CAsset& reissuanceToken, const uint256& entropy, b
|
|||
leaves.push_back(fConfidential ? kTwo : kOne);
|
||||
reissuanceToken = CAsset(ComputeFastMerkleRoot(leaves));
|
||||
}
|
||||
|
||||
/** Add an issuance transaction to the genesis block. Typically used to pre-issue
|
||||
* the policyAsset of a blockchain. The genesis block is not actually validated,
|
||||
* so this transaction simply has to match issuance structure. */
|
||||
void AppendInitialIssuance(CBlock& genesis_block, const COutPoint& prevout, const uint256& contract, const int64_t asset_outputs, const int64_t asset_values, const int64_t reissuance_outputs, const int64_t reissuance_values, const CScript& issuance_destination) {
|
||||
uint256 entropy;
|
||||
GenerateAssetEntropy(entropy, prevout, contract);
|
||||
|
||||
CAsset asset;
|
||||
CalculateAsset(asset, entropy);
|
||||
|
||||
// Re-issuance of policyAsset is always unblinded
|
||||
CAsset reissuance;
|
||||
CalculateReissuanceToken(reissuance, entropy, false);
|
||||
|
||||
// Note: Genesis block isn't actually validated, outputs are entered into utxo db only
|
||||
CMutableTransaction txNew;
|
||||
txNew.nVersion = 1;
|
||||
txNew.vin.resize(1);
|
||||
txNew.vin[0].prevout = prevout;
|
||||
txNew.vin[0].assetIssuance.assetEntropy = contract;
|
||||
txNew.vin[0].assetIssuance.nAmount = CConfidentialValue(asset_values * asset_outputs);
|
||||
txNew.vin[0].assetIssuance.nInflationKeys = CConfidentialValue(reissuance_values * reissuance_outputs);
|
||||
|
||||
for (unsigned int i = 0; i < asset_outputs; i++) {
|
||||
txNew.vout.push_back(CTxOut(asset, CConfidentialValue(asset_values), issuance_destination));
|
||||
}
|
||||
for (unsigned int i = 0; i < reissuance_outputs; i++) {
|
||||
txNew.vout.push_back(CTxOut(reissuance, CConfidentialValue(reissuance_values), issuance_destination));
|
||||
}
|
||||
|
||||
genesis_block.vtx.push_back(MakeTransactionRef(std::move(txNew)));
|
||||
genesis_block.hashMerkleRoot = BlockMerkleRoot(genesis_block);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,6 @@ void CalculateAsset(CAsset& asset, const uint256& entropy);
|
|||
*/
|
||||
void CalculateReissuanceToken(CAsset& reissuanceToken, const uint256& entropy, bool fConfidential);
|
||||
|
||||
void AppendInitialIssuance(CBlock& genesis_block, const COutPoint& prevout, const uint256& contract, const int64_t asset_outputs, const int64_t asset_values, const int64_t reissuance_outputs, const int64_t reissuance_values, const CScript& issuance_destination);
|
||||
|
||||
#endif // BITCOIN_ISSUANCE_H
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
|||
|
||||
// Pad block weight to account for OP_RETURN commitments with two compressed pubkeys
|
||||
for (const auto& commitment : commitments) {
|
||||
CTxOut output(0, commitment);
|
||||
CTxOut output(CAsset(), 0, commitment);
|
||||
nBlockWeight += ::GetSerializeSize(output, PROTOCOL_VERSION)*WITNESS_SCALE_FACTOR;
|
||||
}
|
||||
// END PAK
|
||||
|
|
@ -187,12 +187,23 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
|||
coinbaseTx.vin[0].prevout.SetNull();
|
||||
coinbaseTx.vout.resize(1);
|
||||
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
|
||||
coinbaseTx.vout[0].nAsset = policyAsset;
|
||||
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||
if (g_con_elementsmode) {
|
||||
if(chainparams.GetConsensus().subsidy_asset != policyAsset) {
|
||||
// Only claim the subsidy if it's the same as the policy asset.
|
||||
coinbaseTx.vout[0].nValue = nFees;
|
||||
}
|
||||
// 0-value outputs must be unspendable
|
||||
if (coinbaseTx.vout[0].nValue.GetAmount() == 0) {
|
||||
coinbaseTx.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
||||
}
|
||||
}
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
// ELEMENTS: PAK
|
||||
// Add PAK transition commitments
|
||||
for (unsigned int i = 0; i < commitments.size(); i++) {
|
||||
coinbaseTx.vout.push_back(CTxOut(0, commitments[i]));
|
||||
coinbaseTx.vout.push_back(CTxOut(CAsset(), 0, commitments[i]));
|
||||
}
|
||||
// END PAK
|
||||
pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
|
||||
|
|
|
|||
|
|
@ -54,18 +54,16 @@ bool GetAmountFromParentChainPegin(CAmount& amount, const Sidechain::Bitcoin::CT
|
|||
|
||||
bool GetAmountFromParentChainPegin(CAmount& amount, const CTransaction& txBTC, unsigned int nOut)
|
||||
{
|
||||
//if (!txBTC.vout[nOut].nValue.IsExplicit()) {
|
||||
// return false;
|
||||
//}
|
||||
//if (!txBTC.vout[nOut].nAsset.IsExplicit()) {
|
||||
// return false;
|
||||
//}
|
||||
//if (txBTC.vout[nOut].nAsset.GetAsset() != Params().GetConsensus().parent_pegged_asset) {
|
||||
// return false;
|
||||
//}
|
||||
//amount = txBTC.vout[nOut].nValue.GetAmount();
|
||||
//TODO(rebase) re-enable above for CA/CT
|
||||
amount = txBTC.vout[nOut].nValue;
|
||||
if (!txBTC.vout[nOut].nValue.IsExplicit()) {
|
||||
return false;
|
||||
}
|
||||
if (!txBTC.vout[nOut].nAsset.IsExplicit()) {
|
||||
return false;
|
||||
}
|
||||
if (txBTC.vout[nOut].nAsset.GetAsset() != Params().GetConsensus().parent_pegged_asset) {
|
||||
return false;
|
||||
}
|
||||
amount = txBTC.vout[nOut].nValue.GetAmount();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -278,8 +276,7 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
|
|||
err_msg = "Asset type was not 32 bytes.";
|
||||
return false;
|
||||
}
|
||||
//TODO(rebase) CA
|
||||
//CAsset asset(stack[1]);
|
||||
CAsset asset(stack[1]);
|
||||
|
||||
// Get genesis blockhash
|
||||
if (stack[2].size() != 32) {
|
||||
|
|
@ -350,11 +347,10 @@ bool IsValidPeginWitness(const CScriptWitness& pegin_witness, const COutPoint& p
|
|||
return false;
|
||||
}
|
||||
|
||||
//TODO(rebase) CA
|
||||
//// Check the asset type corresponds to a valid pegged asset (only one for now)
|
||||
//if (asset != Params().GetConsensus().pegged_asset) {
|
||||
// return false;
|
||||
//}
|
||||
// Check the asset type corresponds to a valid pegged asset (only one for now)
|
||||
if (asset != Params().GetConsensus().pegged_asset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finally, validate peg-in via rpc call
|
||||
if (check_depth && gArgs.GetBoolArg("-validatepegin", DEFAULT_VALIDATE_PEGIN)) {
|
||||
|
|
@ -372,9 +368,7 @@ CTxOut GetPeginOutputFromWitness(const CScriptWitness& pegin_witness) {
|
|||
CAmount value;
|
||||
stream >> value;
|
||||
|
||||
//TODO(rebase) CA
|
||||
//return CTxOut(CAsset(pegin_witness.stack[1]), value, CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end()));
|
||||
return CTxOut(value, CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end()));
|
||||
return CTxOut(CAsset(pegin_witness.stack[1]), CConfidentialValue(value), CScript(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end()));
|
||||
}
|
||||
|
||||
bool MatchLiquidWatchman(const CScript& script)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,13 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
|
|||
|
||||
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
|
||||
{
|
||||
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
|
||||
if (!txout.nValue.IsExplicit())
|
||||
return false; // FIXME
|
||||
if (!txout.nAsset.IsExplicit())
|
||||
return false;
|
||||
if (txout.IsFee())
|
||||
return false;
|
||||
return (txout.nValue.GetAmount() < GetDustThreshold(txout, dustRelayFeeIn));
|
||||
}
|
||||
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
|
|
@ -131,21 +137,19 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (whichType == TX_NULL_DATA) {
|
||||
}
|
||||
if (whichType == TX_NULL_DATA) {
|
||||
nDataOut++;
|
||||
if (params.GetEnforcePak() &&
|
||||
txout.scriptPubKey.IsPegoutScript(params.ParentGenesisBlockHash()) &&
|
||||
(!ScriptHasValidPAKProof(txout.scriptPubKey, params.ParentGenesisBlockHash()))) {
|
||||
// TODO(rebase) CT/CA check for asset type
|
||||
txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == Params().GetConsensus().pegged_asset &&
|
||||
(!ScriptHasValidPAKProof(txout.scriptPubKey, params.ParentGenesisBlockHash()))) {
|
||||
reason = "invalid-pegout-proof";
|
||||
return false;
|
||||
}
|
||||
} else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
|
||||
reason = "bare-multisig";
|
||||
return false;
|
||||
} else if (IsDust(txout, ::dustRelayFee)) {
|
||||
} else if ((txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == policyAsset) && IsDust(txout, ::dustRelayFee)) {
|
||||
reason = "dust";
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,21 @@ std::string CTxIn::ToString() const
|
|||
return str;
|
||||
}
|
||||
|
||||
CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
|
||||
CTxOut::CTxOut(const CConfidentialAsset& nAssetIn, const CConfidentialValue& nValueIn, CScript scriptPubKeyIn)
|
||||
{
|
||||
nAsset = nAssetIn;
|
||||
nValue = nValueIn;
|
||||
scriptPubKey = scriptPubKeyIn;
|
||||
}
|
||||
|
||||
std::string CTxOut::ToString() const
|
||||
{
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
|
||||
std::string strAsset;
|
||||
if (nAsset.IsExplicit())
|
||||
strAsset = strprintf("nAsset=%s, ", nAsset.GetAsset().GetHex());
|
||||
if (nAsset.IsCommitment())
|
||||
strAsset = std::string("nAsset=CONFIDENTIAL, ");
|
||||
return strprintf("CTxOut(%snValue=%s, scriptPubKey=%s)", strAsset, (nValue.IsExplicit() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("CONFIDENTIAL")), HexStr(scriptPubKey).substr(0, 30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||
|
|
@ -89,7 +95,8 @@ uint256 CTransaction::GetWitnessOnlyHash() const
|
|||
leaves.reserve(std::max(vin.size(), vout.size()));
|
||||
/* Inputs */
|
||||
for (size_t i = 0; i < vin.size(); ++i) {
|
||||
const CTxInWitness& txinwit = witness.vtxinwit.size() <= i || vin[i].prevout.IsNull() ? CTxInWitness() : witness.vtxinwit[i];
|
||||
// Input has no witness OR is null input(coinbase)
|
||||
const CTxInWitness& txinwit = (witness.vtxinwit.size() <= i || vin[i].prevout.IsNull()) ? CTxInWitness() : witness.vtxinwit[i];
|
||||
leaves.push_back(txinwit.GetHash());
|
||||
}
|
||||
uint256 hashIn = ComputeFastMerkleRoot(leaves);
|
||||
|
|
@ -114,15 +121,19 @@ CTransaction::CTransaction(const CMutableTransaction& tx) :
|
|||
CTransaction::CTransaction(CMutableTransaction&& tx) :
|
||||
vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), witness(std::move(tx.witness)),hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
|
||||
CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
CAmount nValueOut = 0;
|
||||
CAmountMap CTransaction::GetValueOutMap() const {
|
||||
|
||||
CAmountMap values;
|
||||
for (const auto& tx_out : vout) {
|
||||
nValueOut += tx_out.nValue;
|
||||
if (!MoneyRange(tx_out.nValue) || !MoneyRange(nValueOut))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
if (tx_out.nValue.IsExplicit() && tx_out.nAsset.IsExplicit()) {
|
||||
CAmountMap m;
|
||||
m[tx_out.nAsset.GetAsset()] = tx_out.nValue.GetAmount();
|
||||
values += m;
|
||||
if (!MoneyRange(tx_out.nValue.GetAmount()) || !MoneyRange(values[tx_out.nAsset.GetAsset()]))
|
||||
throw std::runtime_error(std::string(__func__) + ": value out of range");
|
||||
}
|
||||
}
|
||||
return nValueOut;
|
||||
return values;
|
||||
}
|
||||
|
||||
unsigned int CTransaction::GetTotalSize() const
|
||||
|
|
|
|||
|
|
@ -237,7 +237,9 @@ public:
|
|||
class CTxOut
|
||||
{
|
||||
public:
|
||||
CAmount nValue;
|
||||
CConfidentialAsset nAsset;
|
||||
CConfidentialValue nValue;
|
||||
CConfidentialNonce nNonce;
|
||||
CScript scriptPubKey;
|
||||
|
||||
CTxOut()
|
||||
|
|
@ -245,30 +247,58 @@ public:
|
|||
SetNull();
|
||||
}
|
||||
|
||||
CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn);
|
||||
CTxOut(const CConfidentialAsset& nAssetIn, const CConfidentialValue& nValueIn, CScript scriptPubKeyIn);
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(nValue);
|
||||
READWRITE(scriptPubKey);
|
||||
if (g_con_elementsmode) {
|
||||
READWRITE(nAsset);
|
||||
READWRITE(nValue);
|
||||
READWRITE(nNonce);
|
||||
READWRITE(scriptPubKey);
|
||||
} else {
|
||||
CAmount value;
|
||||
if (!ser_action.ForRead()) {
|
||||
value = nValue.GetAmount();
|
||||
}
|
||||
READWRITE(value);
|
||||
if (ser_action.ForRead()) {
|
||||
nValue.SetToAmount(value);
|
||||
}
|
||||
READWRITE(scriptPubKey);
|
||||
}
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
nValue = -1;
|
||||
nAsset.SetNull();
|
||||
nValue.SetNull();
|
||||
nNonce.SetNull();
|
||||
scriptPubKey.clear();
|
||||
}
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
return (nValue == -1);
|
||||
if (!g_con_elementsmode) {
|
||||
// Ignore the asset and the nonce in compatibility mode.
|
||||
return nValue.IsNull() && scriptPubKey.empty();
|
||||
}
|
||||
|
||||
return nAsset.IsNull() && nValue.IsNull() && nNonce.IsNull() && scriptPubKey.empty();
|
||||
}
|
||||
|
||||
bool IsFee() const {
|
||||
return g_con_elementsmode && scriptPubKey == CScript()
|
||||
&& nValue.IsExplicit() && nAsset.IsExplicit();
|
||||
}
|
||||
|
||||
friend bool operator==(const CTxOut& a, const CTxOut& b)
|
||||
{
|
||||
return (a.nValue == b.nValue &&
|
||||
return (a.nAsset == b.nAsset &&
|
||||
a.nValue == b.nValue &&
|
||||
a.nNonce == b.nNonce &&
|
||||
a.scriptPubKey == b.scriptPubKey);
|
||||
}
|
||||
|
||||
|
|
@ -482,7 +512,7 @@ public:
|
|||
uint256 GetWitnessOnlyHash() const;
|
||||
|
||||
// Return sum of txouts.
|
||||
CAmount GetValueOut() const;
|
||||
CAmountMap GetValueOutMap() const;
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// inputs must be known to compute value in.
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@
|
|||
uint256 CTxInWitness::GetHash() const
|
||||
{
|
||||
std::vector<uint256> leaves;
|
||||
//TODO(rebase) CA/CT
|
||||
//leaves.push_back(SerializeHash(vchIssuanceAmountRangeproof, SER_GETHASH, 0));
|
||||
//leaves.push_back(SerializeHash(vchInflationKeysRangeproof, SER_GETHASH, 0));
|
||||
leaves.push_back(SerializeHash(vchIssuanceAmountRangeproof, SER_GETHASH, 0));
|
||||
leaves.push_back(SerializeHash(vchInflationKeysRangeproof, SER_GETHASH, 0));
|
||||
leaves.push_back(SerializeHash(scriptWitness.stack, SER_GETHASH, 0));
|
||||
leaves.push_back(SerializeHash(m_pegin_witness.stack, SER_GETHASH, 0));
|
||||
return ComputeFastMerkleRoot(leaves);
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ public:
|
|||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
//READWRITE(vchIssuanceAmountRangeproof);
|
||||
//READWRITE(vchInflationKeysRangeproof);
|
||||
READWRITE(vchIssuanceAmountRangeproof);
|
||||
READWRITE(vchInflationKeysRangeproof);
|
||||
READWRITE(scriptWitness.stack);
|
||||
READWRITE(m_pegin_witness.stack);
|
||||
}
|
||||
|
|
@ -105,15 +105,13 @@ public:
|
|||
for (size_t n = 0; n < vtxinwit.size(); n++) {
|
||||
READWRITE(vtxinwit[n]);
|
||||
}
|
||||
//TODO(rebase) CA/CT
|
||||
//for (size_t n = 0; n < vtxoutwit.size(); n++) {
|
||||
// READWRITE(vtxoutwit[n]);
|
||||
//}
|
||||
//TODO(stevenroose) re-enabled after testing
|
||||
//if (IsNull()) {
|
||||
// /* It's illegal to encode a witness when all vtxinwit and vtxoutwit entries are empty. */
|
||||
// throw std::ios_base::failure("Superfluous witness record");
|
||||
//}
|
||||
for (size_t n = 0; n < vtxoutwit.size(); n++) {
|
||||
READWRITE(vtxoutwit[n]);
|
||||
}
|
||||
if (IsNull()) {
|
||||
/* It's illegal to encode a witness when all vtxinwit and vtxoutwit entries are empty. */
|
||||
throw std::ios_base::failure("Superfluous witness record");
|
||||
}
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue