mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Merge ElementsProject/elements#1002: Implement Taproot Sighash
14f93579a5Add pegins and issuance test (sanket1729)edf8455fe4Fix bug in CAssetIssuance decoding (sanket1729)cdd75d4251Update OP_SUCCESS for elements with allowed opcodes (sanket1729)4618097ab4Implement taphash for elements (sanket1729)6c985308d7Implement Taphash in test framework (sanket1729)a26f6fead6Expose only blockchain hash twice in header (sanket1729)afb9e7b727taproot: feed genesis hash and parent pegged asset to sighash function (Andrew Poelstra) Pull request description: ACKs for top commit: apoelstra: ACK14f93579a5Tree-SHA512: f0a3f6ef9f8958bc948cc42375600767f39aadc0dac096fe8e7823dc69ddc4204360e504af7801d05bb19ae4e6ace6a271842531c192e330167381cf2690c856
This commit is contained in:
commit
1ba24fe9b3
17 changed files with 458 additions and 77 deletions
|
|
@ -68,6 +68,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
|
|||
CDataStream streamVal(SER_NETWORK, PROTOCOL_VERSION);
|
||||
streamVal << txCredit.vout[0].nValue;
|
||||
int csuccess = bitcoinconsensus_verify_script_with_amount(
|
||||
NULL,
|
||||
txCredit.vout[0].scriptPubKey.data(),
|
||||
txCredit.vout[0].scriptPubKey.size(),
|
||||
(const unsigned char*)&streamVal[0], streamVal.size(),
|
||||
|
|
|
|||
|
|
@ -97,7 +97,8 @@ public:
|
|||
const CCheckpointData& Checkpoints() const { return checkpointData; }
|
||||
const ChainTxData& TxData() const { return chainTxData; }
|
||||
// ELEMENTS extra fields:
|
||||
const uint256 ParentGenesisBlockHash() const { return parentGenesisBlockHash; }
|
||||
const uint256& ParentGenesisBlockHash() const { return parentGenesisBlockHash; }
|
||||
const uint256& HashGenesisBlock() const { return consensus.hashGenesisBlock; }
|
||||
bool anyonecanspend_aremine;
|
||||
const std::string& ParentBech32HRP() const { return parent_bech32_hrp; }
|
||||
const std::string& ParentBlech32HRP() const { return parent_blech32_hrp; }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <primitives/transaction.h>
|
||||
#include <pubkey.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <streams.h>
|
||||
#include <version.h>
|
||||
|
||||
namespace {
|
||||
|
|
@ -76,7 +77,8 @@ static bool verify_flags(unsigned int flags)
|
|||
return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
|
||||
}
|
||||
|
||||
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CConfidentialValue amount,
|
||||
static int verify_script(const unsigned char *hash_genesis_block,
|
||||
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CConfidentialValue amount,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
|
||||
{
|
||||
|
|
@ -94,7 +96,9 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
|
|||
// Regardless of the verification result, the tx did not error.
|
||||
set_error(err, bitcoinconsensus_ERR_OK);
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
auto hash_genesis_block_ = hash_genesis_block ? uint256{hash_genesis_block, 32} : uint256{};
|
||||
PrecomputedTransactionData txdata(hash_genesis_block_);
|
||||
txdata.Init(tx, {});
|
||||
const CScriptWitness* pScriptWitness = (tx.witness.vtxinwit.size() > nIn ? &tx.witness.vtxinwit[nIn].scriptWitness : NULL);
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), pScriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
|
||||
} catch (const std::exception&) {
|
||||
|
|
@ -102,7 +106,8 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
|
|||
}
|
||||
}
|
||||
|
||||
int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
int bitcoinconsensus_verify_script_with_amount(const unsigned char *hash_genesis_block,
|
||||
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *amount, unsigned int amountLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
|
||||
|
|
@ -112,14 +117,15 @@ int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey
|
|||
CConfidentialValue am;
|
||||
stream >> am;
|
||||
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
return ::verify_script(hash_genesis_block, scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
int bitcoinconsensus_verify_script(const unsigned char *hash_genesis_block,
|
||||
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
|
||||
{
|
||||
|
|
@ -128,7 +134,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
|
|||
}
|
||||
|
||||
CConfidentialValue am(0);
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
return ::verify_script(hash_genesis_block, scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
}
|
||||
|
||||
unsigned int bitcoinconsensus_version()
|
||||
|
|
|
|||
|
|
@ -64,11 +64,13 @@ enum
|
|||
/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under
|
||||
/// the additional constraints specified by flags.
|
||||
/// If not nullptr, err will contain an error/success code for the operation
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *hash_genesis_block,
|
||||
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
|
||||
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *hash_genesis_block,
|
||||
const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *amount, unsigned int amountLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
|
||||
|
|
|
|||
|
|
@ -1757,6 +1757,17 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all outpoint flags of a tx. */
|
||||
template <class T>
|
||||
uint256 GetOutpointFlagsSHA256(const T& txTo)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
for (const auto& txin : txTo.vin) {
|
||||
ss << (unsigned char) ((!txin.assetIssuance.IsNull() << 7) + (txin.m_is_pegin << 6));
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all prevouts of a tx. */
|
||||
template <class T>
|
||||
uint256 GetPrevoutsSHA256(const T& txTo)
|
||||
|
|
@ -1779,7 +1790,8 @@ uint256 GetSequencesSHA256(const T& txTo)
|
|||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all txouts of a tx. */
|
||||
/** Compute the (single) SHA256 of the concatenation of all issuances of a tx. */
|
||||
// Used for segwitv0/taproot sighash calculation
|
||||
template <class T>
|
||||
uint256 GetIssuanceSHA256(const T& txTo)
|
||||
{
|
||||
|
|
@ -1793,6 +1805,34 @@ uint256 GetIssuanceSHA256(const T& txTo)
|
|||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all output witnesses
|
||||
* (rangeproof and surjection proof) in `CTxWitness`*/
|
||||
// Used in taphash calculation
|
||||
template <class T>
|
||||
uint256 GetOutputWitnessesSHA256(const T& txTo)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
for (const auto& outwit : txTo.witness.vtxoutwit) {
|
||||
ss << outwit;
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all input issuance witnesses
|
||||
* (vchIssuanceAmountRangeproof and vchInflationKeysRangeproof proof) in `CTxInWitness`*/
|
||||
// Used in taphash calculation
|
||||
template <class T>
|
||||
uint256 GetIssuanceRangeproofsSHA256(const T& txTo)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
for (const auto& inwit : txTo.witness.vtxinwit) {
|
||||
ss << inwit.vchIssuanceAmountRangeproof;
|
||||
ss << inwit.vchInflationKeysRangeproof;
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
// Compute a (single) SHA256 of the concatenation of all outputs
|
||||
template <class T>
|
||||
uint256 GetOutputsSHA256(const T& txTo)
|
||||
{
|
||||
|
|
@ -1803,11 +1843,13 @@ uint256 GetOutputsSHA256(const T& txTo)
|
|||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
|
||||
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||
/** Compute the (single) SHA256 of the concatenation of all asset and amounts commitments spent by a tx. */
|
||||
// Elements TapHash only
|
||||
uint256 GetSpentAssetsAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||
{
|
||||
CHashWriter ss(SER_GETHASH, 0);
|
||||
for (const auto& txout : outputs_spent) {
|
||||
ss << txout.nAsset;
|
||||
ss << txout.nValue;
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
|
|
@ -1878,17 +1920,21 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
|
|||
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
|
||||
m_sequences_single_hash = GetSequencesSHA256(txTo);
|
||||
m_outputs_single_hash = GetOutputsSHA256(txTo);
|
||||
m_issuances_single_hash = GetIssuanceSHA256(txTo);
|
||||
}
|
||||
if (uses_bip143_segwit) {
|
||||
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
|
||||
hashSequence = SHA256Uint256(m_sequences_single_hash);
|
||||
hashIssuance = SHA256Uint256(GetIssuanceSHA256(txTo));
|
||||
hashIssuance = SHA256Uint256(m_issuances_single_hash);
|
||||
hashOutputs = SHA256Uint256(m_outputs_single_hash);
|
||||
hashRangeproofs = GetRangeproofsHash(txTo);
|
||||
m_bip143_segwit_ready = true;
|
||||
}
|
||||
if (uses_bip341_taproot) {
|
||||
m_spent_amounts_single_hash = GetSpentAmountsSHA256(m_spent_outputs);
|
||||
m_outpoints_flag_single_hash = GetOutpointFlagsSHA256(txTo);
|
||||
m_spent_asset_amounts_single_hash = GetSpentAssetsAmountsSHA256(m_spent_outputs);
|
||||
m_issuance_rangeproofs_single_hash = GetIssuanceRangeproofsSHA256(txTo);
|
||||
m_output_witnesses_single_hash = GetOutputWitnessesSHA256(txTo);
|
||||
m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs);
|
||||
m_bip341_taproot_ready = true;
|
||||
}
|
||||
|
|
@ -1896,6 +1942,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
|
|||
|
||||
template <class T>
|
||||
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
|
||||
: PrecomputedTransactionData(uint256{})
|
||||
{
|
||||
Init(txTo, {});
|
||||
}
|
||||
|
|
@ -1906,10 +1953,14 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
|
|||
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
||||
|
||||
static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
|
||||
static const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
|
||||
static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
|
||||
static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
|
||||
|
||||
static const CHashWriter HASHER_TAPLEAF_ELEMENTS = TaggedHash("TapLeaf/elements");
|
||||
static const CHashWriter HASHER_TAPBRANCH_ELEMENTS = TaggedHash("TapBranch/elements");
|
||||
static const CHashWriter HASHER_TAPTWEAK_ELEMENTS = TaggedHash("TapTweak/elements");
|
||||
static const CHashWriter HASHER_TAPSIGHASH_ELEMENTS = TaggedHash("TapSighash/elements");
|
||||
|
||||
PrecomputedTransactionData::PrecomputedTransactionData(const uint256& hash_genesis_block)
|
||||
: m_tapsighash_hasher(CHashWriter(HASHER_TAPSIGHASH_ELEMENTS) << hash_genesis_block << hash_genesis_block) {}
|
||||
|
||||
template<typename T>
|
||||
bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache)
|
||||
|
|
@ -1934,11 +1985,11 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata
|
|||
assert(in_pos < tx_to.vin.size());
|
||||
assert(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready);
|
||||
|
||||
CHashWriter ss = HASHER_TAPSIGHASH;
|
||||
CHashWriter ss = cache.m_tapsighash_hasher;
|
||||
|
||||
// Epoch
|
||||
static constexpr uint8_t EPOCH = 0;
|
||||
ss << EPOCH;
|
||||
// no epoch in elements taphash
|
||||
// static constexpr uint8_t EPOCH = 0;
|
||||
// ss << EPOCH;
|
||||
|
||||
// Hash type
|
||||
const uint8_t output_type = (hash_type == SIGHASH_DEFAULT) ? SIGHASH_ALL : (hash_type & SIGHASH_OUTPUT_MASK); // Default (no sighash byte) is equivalent to SIGHASH_ALL
|
||||
|
|
@ -1950,37 +2001,56 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata
|
|||
ss << tx_to.nVersion;
|
||||
ss << tx_to.nLockTime;
|
||||
if (input_type != SIGHASH_ANYONECANPAY) {
|
||||
ss << cache.m_outpoints_flag_single_hash;
|
||||
ss << cache.m_prevouts_single_hash;
|
||||
ss << cache.m_spent_amounts_single_hash;
|
||||
ss << cache.m_spent_asset_amounts_single_hash;
|
||||
ss << cache.m_spent_scripts_single_hash;
|
||||
ss << cache.m_sequences_single_hash;
|
||||
ss << cache.m_issuances_single_hash;
|
||||
ss << cache.m_issuance_rangeproofs_single_hash;
|
||||
}
|
||||
if (output_type == SIGHASH_ALL) {
|
||||
ss << cache.m_outputs_single_hash;
|
||||
ss << cache.m_output_witnesses_single_hash;
|
||||
}
|
||||
|
||||
// Data about the input/prevout being spent
|
||||
assert(execdata.m_annex_init);
|
||||
const bool have_annex = execdata.m_annex_present;
|
||||
const uint8_t spend_type = (ext_flag << 1) + (have_annex ? 1 : 0); // The low bit indicates whether an annex is present.
|
||||
ss << spend_type;
|
||||
if (input_type == SIGHASH_ANYONECANPAY) {
|
||||
ss << (unsigned char) ((!tx_to.vin[in_pos].assetIssuance.IsNull() << 7) + (tx_to.vin[in_pos].m_is_pegin << 6));
|
||||
ss << tx_to.vin[in_pos].prevout;
|
||||
ss << cache.m_spent_outputs[in_pos];
|
||||
ss << cache.m_spent_outputs[in_pos].nAsset;
|
||||
ss << cache.m_spent_outputs[in_pos].nValue;
|
||||
ss << cache.m_spent_outputs[in_pos].scriptPubKey;
|
||||
ss << tx_to.vin[in_pos].nSequence;
|
||||
if (tx_to.vin[in_pos].assetIssuance.IsNull()) {
|
||||
ss << (unsigned char)0;
|
||||
} else {
|
||||
ss << tx_to.vin[in_pos].assetIssuance;
|
||||
|
||||
CHashWriter sha_single_input_issuance_witness(SER_GETHASH, 0);
|
||||
sha_single_input_issuance_witness << tx_to.witness.vtxinwit[in_pos].vchIssuanceAmountRangeproof;
|
||||
sha_single_input_issuance_witness << tx_to.witness.vtxinwit[in_pos].vchInflationKeysRangeproof;
|
||||
ss << sha_single_input_issuance_witness.GetSHA256();
|
||||
}
|
||||
} else {
|
||||
ss << in_pos;
|
||||
}
|
||||
if (have_annex) {
|
||||
ss << execdata.m_annex_hash;
|
||||
}
|
||||
|
||||
// Data about the output (if only one).
|
||||
if (output_type == SIGHASH_SINGLE) {
|
||||
if (in_pos >= tx_to.vout.size()) return false;
|
||||
CHashWriter sha_single_output(SER_GETHASH, 0);
|
||||
sha_single_output << tx_to.vout[in_pos];
|
||||
ss << sha_single_output.GetSHA256();
|
||||
|
||||
CHashWriter sha_single_output_witness(SER_GETHASH, 0);
|
||||
sha_single_output_witness << tx_to.witness.vtxoutwit[in_pos];
|
||||
ss << sha_single_output_witness.GetSHA256();
|
||||
}
|
||||
|
||||
// Additional data for BIP 342 signatures
|
||||
|
|
@ -2297,10 +2367,10 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
|
|||
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
|
||||
const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))};
|
||||
const XOnlyPubKey q{uint256(program)};
|
||||
tapleaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256();
|
||||
tapleaf_hash = (CHashWriter(HASHER_TAPLEAF_ELEMENTS) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256();
|
||||
uint256 k = tapleaf_hash;
|
||||
for (int i = 0; i < path_len; ++i) {
|
||||
CHashWriter ss_branch{HASHER_TAPBRANCH};
|
||||
CHashWriter ss_branch = CHashWriter{HASHER_TAPBRANCH_ELEMENTS};
|
||||
Span<const unsigned char> node(control.data() + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE);
|
||||
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
|
||||
ss_branch << k << node;
|
||||
|
|
@ -2309,7 +2379,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
|
|||
}
|
||||
k = ss_branch.GetSHA256();
|
||||
}
|
||||
k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256();
|
||||
k = (CHashWriter(HASHER_TAPTWEAK_ELEMENTS) << MakeSpan(p) << k).GetSHA256();
|
||||
return q.CheckPayToContract(p, k, control[0] & 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef BITCOIN_SCRIPT_INTERPRETER_H
|
||||
#define BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include <hash.h>
|
||||
#include <script/script_error.h>
|
||||
#include <span.h>
|
||||
#include <primitives/transaction.h>
|
||||
|
|
@ -166,19 +167,29 @@ struct PrecomputedTransactionData
|
|||
uint256 m_outputs_single_hash;
|
||||
uint256 m_spent_amounts_single_hash;
|
||||
uint256 m_spent_scripts_single_hash;
|
||||
//! Whether the 5 fields above are initialized.
|
||||
// Elements
|
||||
uint256 m_outpoints_flag_single_hash;
|
||||
uint256 m_spent_asset_amounts_single_hash;
|
||||
uint256 m_issuances_single_hash;
|
||||
uint256 m_output_witnesses_single_hash;
|
||||
uint256 m_issuance_rangeproofs_single_hash;
|
||||
//! Whether the 10 fields above are initialized.
|
||||
bool m_bip341_taproot_ready = false;
|
||||
|
||||
// BIP143 precomputed data (double-SHA256).
|
||||
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance, hashRangeproofs;
|
||||
//! Whether the 3 fields above are initialized.
|
||||
//! Whether the 5 fields above are initialized.
|
||||
bool m_bip143_segwit_ready = false;
|
||||
|
||||
std::vector<CTxOut> m_spent_outputs;
|
||||
//! Whether m_spent_outputs is initialized.
|
||||
bool m_spent_outputs_ready = false;
|
||||
|
||||
PrecomputedTransactionData() = default;
|
||||
//! ELEMENTS: parent genesis hash
|
||||
CHashWriter m_tapsighash_hasher;
|
||||
|
||||
explicit PrecomputedTransactionData(const uint256& hash_genesis_block);
|
||||
explicit PrecomputedTransactionData() : PrecomputedTransactionData(uint256{}) {}
|
||||
|
||||
template <class T>
|
||||
void Init(const T& tx, std::vector<CTxOut>&& spent_outputs);
|
||||
|
|
|
|||
|
|
@ -411,8 +411,10 @@ bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator en
|
|||
|
||||
bool IsOpSuccess(const opcodetype& opcode)
|
||||
{
|
||||
return opcode == 80 || opcode == 98 || (opcode >= 126 && opcode <= 129) ||
|
||||
(opcode >= 131 && opcode <= 134) || (opcode >= 137 && opcode <= 138) ||
|
||||
(opcode >= 141 && opcode <= 142) || (opcode >= 149 && opcode <= 153) ||
|
||||
(opcode >= 187 && opcode <= 254);
|
||||
// ELEMENTS: Don't mark opcodes (OP_CAT, OP_SUBSTR, OP_LEFT, OP_RIGHT) as OP_SUCCESS
|
||||
return opcode == 80 || opcode == 98 || (opcode >= 137 && opcode <= 138) ||
|
||||
// ELEMENTS: Don't mark OP_INVERT , OP_AND, OP_OR, OP_XOR. OP_LSHIFT, OP_RSHIFT as success
|
||||
(opcode >= 141 && opcode <= 142) || (opcode >= 149 && opcode <= 151) ||
|
||||
// ELEMENTS: Exclude OP_DETERMINISTICRANDOM, OP_CHECKSIGFROMSTACK(VERIFY), OP_SUBSTRLAZY
|
||||
(opcode >= 187 && opcode <= 191) || (opcode >= 196 && opcode <= 254);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
const std::vector<uint8_t> random_bytes_1 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
||||
const std::vector<uint8_t> random_bytes_2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
|
||||
const uint256 random_hash = ConsumeUInt256(fuzzed_data_provider);
|
||||
|
||||
const std::optional<CConfidentialValue> money = ConsumeDeserializable<CConfidentialValue>(fuzzed_data_provider);
|
||||
bitcoinconsensus_error err;
|
||||
bitcoinconsensus_error* err_p = fuzzed_data_provider.ConsumeBool() ? &err : nullptr;
|
||||
|
|
@ -26,10 +28,10 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||
if ((flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
|
||||
return;
|
||||
}
|
||||
(void)bitcoinconsensus_verify_script(random_bytes_1.data(), random_bytes_1.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
|
||||
(void)bitcoinconsensus_verify_script(random_hash.begin() ,random_bytes_1.data(), random_bytes_1.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
|
||||
if (money) {
|
||||
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
data_stream << *money;
|
||||
(void)bitcoinconsensus_verify_script_with_amount(random_bytes_1.data(), random_bytes_1.size(), (unsigned char*) data_stream.data(), data_stream.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
|
||||
(void)bitcoinconsensus_verify_script_with_amount(random_hash.begin(), random_bytes_1.data(), random_bytes_1.size(), (unsigned char*) data_stream.data(), data_stream.size(), random_bytes_2.data(), random_bytes_2.size(), n_in, flags, err_p);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,10 +159,10 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
|
|||
if (libconsensus_flags == flags) {
|
||||
int expectedSuccessCode = expect ? 1 : 0;
|
||||
if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal[0], streamVal.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal[0], streamVal.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
} else {
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal0[0], streamVal0.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&streamVal0[0], streamVal0.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1524,7 +1524,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_returns_true)
|
|||
stream << spendTx;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 1);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_OK);
|
||||
}
|
||||
|
|
@ -1547,7 +1547,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_index_err)
|
|||
stream << spendTx;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 0);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_INDEX);
|
||||
}
|
||||
|
|
@ -1570,7 +1570,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_size)
|
|||
stream << spendTx;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size() * 2, nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size() * 2, nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 0);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
|
||||
}
|
||||
|
|
@ -1593,7 +1593,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_serialization)
|
|||
stream << 0xffffffff;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 0);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_DESERIALIZE);
|
||||
}
|
||||
|
|
@ -1616,7 +1616,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_amount_required_err)
|
|||
stream << spendTx;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 0);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED);
|
||||
}
|
||||
|
|
@ -1639,7 +1639,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags)
|
|||
stream << spendTx;
|
||||
|
||||
bitcoinconsensus_error err;
|
||||
int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
int result = bitcoinconsensus_verify_script(NULL, scriptPubKey.data(), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), nIn, libconsensus_flags, &err);
|
||||
BOOST_CHECK_EQUAL(result, 0);
|
||||
BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_INVALID_FLAGS);
|
||||
}
|
||||
|
|
@ -1685,12 +1685,14 @@ static void AssetTest(const UniValue& test)
|
|||
size_t idx = test["index"].get_int64();
|
||||
unsigned int test_flags = ParseScriptFlags(test["flags"].get_str());
|
||||
bool fin = test.exists("final") && test["final"].get_bool();
|
||||
// ELEMENTS FIXME: update feature_taproot.py --dumptests to actually output these
|
||||
uint256 hash_genesis_block = test.exists("hash_genesis_block") ? uint256S(test["hash_genesis_block"].get_str()) : uint256{};
|
||||
|
||||
if (test.exists("success")) {
|
||||
mtx.vin[idx].scriptSig = ScriptFromHex(test["success"]["scriptSig"].get_str());
|
||||
mtx.witness.vtxinwit[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]);
|
||||
CTransaction tx(mtx);
|
||||
PrecomputedTransactionData txdata;
|
||||
PrecomputedTransactionData txdata(hash_genesis_block);
|
||||
txdata.Init(tx, std::vector<CTxOut>(prevouts));
|
||||
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
|
||||
for (const auto flags : ALL_CONSENSUS_FLAGS) {
|
||||
|
|
@ -1707,7 +1709,7 @@ static void AssetTest(const UniValue& test)
|
|||
mtx.vin[idx].scriptSig = ScriptFromHex(test["failure"]["scriptSig"].get_str());
|
||||
mtx.witness.vtxinwit[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]);
|
||||
CTransaction tx(mtx);
|
||||
PrecomputedTransactionData txdata;
|
||||
PrecomputedTransactionData txdata(hash_genesis_block);
|
||||
txdata.Init(tx, std::vector<CTxOut>(prevouts));
|
||||
CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata);
|
||||
for (const auto flags : ALL_CONSENSUS_FLAGS) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ base_blob<BITS>::base_blob(const std::vector<unsigned char>& vch)
|
|||
memcpy(m_data, vch.data(), sizeof(m_data));
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
base_blob<BITS>::base_blob(const unsigned char* data, size_t len)
|
||||
{
|
||||
assert(len == sizeof(m_data));
|
||||
memcpy(m_data, data, sizeof(m_data));
|
||||
}
|
||||
|
||||
template <unsigned int BITS>
|
||||
std::string base_blob<BITS>::GetHex() const
|
||||
{
|
||||
|
|
@ -68,6 +75,7 @@ std::string base_blob<BITS>::ToString() const
|
|||
|
||||
// Explicit instantiations for base_blob<160>
|
||||
template base_blob<160>::base_blob(const std::vector<unsigned char>&);
|
||||
template base_blob<160>::base_blob(const unsigned char*, size_t);
|
||||
template std::string base_blob<160>::GetHex() const;
|
||||
template std::string base_blob<160>::ToString() const;
|
||||
template void base_blob<160>::SetHex(const char*);
|
||||
|
|
@ -75,6 +83,7 @@ template void base_blob<160>::SetHex(const std::string&);
|
|||
|
||||
// Explicit instantiations for base_blob<256>
|
||||
template base_blob<256>::base_blob(const std::vector<unsigned char>&);
|
||||
template base_blob<256>::base_blob(const unsigned char*, size_t);
|
||||
template std::string base_blob<256>::GetHex() const;
|
||||
template std::string base_blob<256>::ToString() const;
|
||||
template void base_blob<256>::SetHex(const char*);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public:
|
|||
constexpr explicit base_blob(uint8_t v) : m_data{v} {}
|
||||
|
||||
explicit base_blob(const std::vector<unsigned char>& vch);
|
||||
explicit base_blob(const unsigned char* data, size_t len);
|
||||
|
||||
bool IsNull() const
|
||||
{
|
||||
|
|
@ -126,6 +127,7 @@ public:
|
|||
constexpr uint256() {}
|
||||
constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {}
|
||||
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
|
||||
explicit uint256(const unsigned char* data, size_t len) : base_blob<256>(data, len) {}
|
||||
static const uint256 ZERO;
|
||||
static const uint256 ONE;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1120,7 +1120,7 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
|
|||
// scripts (ie, other policy checks pass). We perform the inexpensive
|
||||
// checks first and avoid hashing and signature verification unless those
|
||||
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
|
||||
PrecomputedTransactionData txdata;
|
||||
PrecomputedTransactionData txdata(args.m_chainparams.HashGenesisBlock());
|
||||
|
||||
if (!PolicyScriptChecks(args, workspace, txdata)) return false;
|
||||
|
||||
|
|
@ -2296,7 +2296,10 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
|||
// doesn't invalidate pointers into the vector, and keep txsdata in scope
|
||||
// for as long as `control`.
|
||||
CCheckQueueControl<CCheck> control(fScriptChecks && g_parallel_script_checks ? &scriptcheckqueue : nullptr);
|
||||
std::vector<PrecomputedTransactionData> txsdata(block.vtx.size());
|
||||
std::vector<PrecomputedTransactionData> txsdata;
|
||||
for (unsigned int i = 0; i< block.vtx.size(); i++ ){
|
||||
txsdata.push_back(PrecomputedTransactionData(chainparams.HashGenesisBlock()));
|
||||
}
|
||||
|
||||
std::vector<int> prevheights;
|
||||
CAmountMap fee_map;
|
||||
|
|
|
|||
190
test/functional/feature_taphash_pegins_issuances.py
Executable file
190
test/functional/feature_taphash_pegins_issuances.py
Executable file
|
|
@ -0,0 +1,190 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2014-2016 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#
|
||||
# Test for taproot sighash algorithm with pegins and issuances
|
||||
|
||||
from test_framework.key import ECKey, ECPubKey, compute_xonly_pubkey, generate_privkey, sign_schnorr, tweak_add_privkey, tweak_add_pubkey, verify_schnorr
|
||||
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, CTxOutValue, CTxOutWitness, FromHex, uint256_from_str
|
||||
from test_framework.test_framework import BitcoinTestFramework, SkipTest
|
||||
from test_framework.script import TaprootSignatureHash, taproot_construct, taproot_pad_sighash_ty, SIGHASH_DEFAULT, SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, SIGHASH_ANYONECANPAY
|
||||
|
||||
VALID_SIGHASHES_ECDSA = [
|
||||
SIGHASH_ALL,
|
||||
SIGHASH_NONE,
|
||||
SIGHASH_SINGLE,
|
||||
SIGHASH_ANYONECANPAY + SIGHASH_ALL,
|
||||
SIGHASH_ANYONECANPAY + SIGHASH_NONE,
|
||||
SIGHASH_ANYONECANPAY + SIGHASH_SINGLE
|
||||
]
|
||||
|
||||
VALID_SIGHASHES_TAPROOT = [SIGHASH_DEFAULT] + VALID_SIGHASHES_ECDSA
|
||||
|
||||
class TapHashPeginTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
self.extra_args = [
|
||||
["-initialfreecoins=2100000000000000",
|
||||
"-anyonecanspendaremine=1",
|
||||
"-blindedaddresses=1",
|
||||
"-validatepegin=0",
|
||||
"-con_parent_chain_signblockscript=51",
|
||||
"-parentscriptprefix=75",
|
||||
"-parent_bech32_hrp=ert",
|
||||
"-minrelaytxfee=0",
|
||||
"-maxtxfee=100.0",
|
||||
]]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.setup_nodes()
|
||||
|
||||
def create_taproot_utxo(self):
|
||||
# modify the transaction to add one output that should spend previous taproot
|
||||
# Create a taproot prevout
|
||||
addr = self.nodes[0].getnewaddress()
|
||||
|
||||
sec = generate_privkey()
|
||||
pub = compute_xonly_pubkey(sec)[0]
|
||||
tap = taproot_construct(pub)
|
||||
spk = tap.scriptPubKey
|
||||
tweak = tap.tweak
|
||||
|
||||
unconf_addr = self.nodes[0].getaddressinfo(addr)['unconfidential']
|
||||
|
||||
raw_tx = self.nodes[0].createrawtransaction([], [{unconf_addr: 1.2}])
|
||||
# edit spk directly, no way to get new address.
|
||||
# would need to implement bech32m in python
|
||||
tx = FromHex(CTransaction(), raw_tx)
|
||||
tx.vout[0].scriptPubKey = spk
|
||||
tx.vout[0].nValue = CTxOutValue(12*10**7)
|
||||
raw_hex = tx.serialize().hex()
|
||||
|
||||
fund_tx = self.nodes[0].fundrawtransaction(raw_hex, False, )["hex"]
|
||||
fund_tx = FromHex(CTransaction(), fund_tx)
|
||||
|
||||
# Createrawtransaction might rearrage txouts
|
||||
prev_vout = None
|
||||
for i, out in enumerate(fund_tx.vout):
|
||||
if spk == out.scriptPubKey:
|
||||
prev_vout = i
|
||||
|
||||
tx = self.nodes[0].blindrawtransaction(fund_tx.serialize().hex())
|
||||
signed_raw_tx = self.nodes[0].signrawtransactionwithwallet(tx)
|
||||
_txid = self.nodes[0].sendrawtransaction(signed_raw_tx['hex'])
|
||||
tx = FromHex(CTransaction(), signed_raw_tx['hex'])
|
||||
tx.rehash()
|
||||
self.nodes[0].generate(1)
|
||||
last_blk = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
|
||||
assert(tx.hash in last_blk['tx'])
|
||||
|
||||
return tx, prev_vout, spk, sec, pub, tweak
|
||||
|
||||
def pegin_test(self, sighash_ty):
|
||||
|
||||
# Peg-in prep:
|
||||
# Hack: since we're not validating peg-ins in parent chain, just make
|
||||
# both the funding and claim tx on same chain (printing money)
|
||||
fund_info = self.nodes[0].getpeginaddress()
|
||||
peg_id = self.nodes[0].sendtoaddress(fund_info["mainchain_address"], 1)
|
||||
raw_peg_tx = self.nodes[0].gettransaction(peg_id)["hex"]
|
||||
peg_txid = self.nodes[0].sendrawtransaction(raw_peg_tx)
|
||||
self.nodes[0].generate(101)
|
||||
peg_prf = self.nodes[0].gettxoutproof([peg_txid])
|
||||
claim_script = fund_info["claim_script"]
|
||||
|
||||
# Create a pegin transaction
|
||||
# We have to manually supply claim script, otherwise the wallet will pick
|
||||
raw_claim = self.nodes[0].createrawpegin(raw_peg_tx, peg_prf, claim_script)
|
||||
raw_claim = FromHex(CTransaction(), raw_claim['hex'])
|
||||
|
||||
# Create a taproot utxo
|
||||
tx, prev_vout, spk, sec, pub, tweak = self.create_taproot_utxo()
|
||||
|
||||
# Spend the pegin and taproot tx together
|
||||
raw_claim.vin.append(CTxIn(COutPoint(tx.sha256, prev_vout)))
|
||||
raw_claim.vout.append(CTxOut(nValue = CTxOutValue(12 * 10**7), scriptPubKey = spk)) # send back to self
|
||||
|
||||
signed = self.nodes[0].signrawtransactionwithwallet(raw_claim.serialize().hex())
|
||||
raw_claim = FromHex(CTransaction(), signed['hex'])
|
||||
genesis_hash = uint256_from_str(bytes.fromhex(self.nodes[0].getblockhash(0))[::-1])
|
||||
peg_utxo = CTxOut()
|
||||
peg_utxo.from_pegin_witness_data(raw_claim.wit.vtxinwit[0].peginWitness)
|
||||
msg = TaprootSignatureHash(raw_claim, [peg_utxo, tx.vout[prev_vout]], sighash_ty, genesis_hash, 1)
|
||||
|
||||
# compute the tweak
|
||||
tweak_sk = tweak_add_privkey(sec, tweak)
|
||||
sig = sign_schnorr(tweak_sk, msg)
|
||||
raw_claim.wit.vtxinwit[1].scriptWitness.stack = [taproot_pad_sighash_ty(sig, sighash_ty)]
|
||||
pub_tweak = tweak_add_pubkey(pub, tweak)[0]
|
||||
assert(verify_schnorr(pub_tweak, sig, msg))
|
||||
# Since we add in/outputs the min feerate is no longer maintained.
|
||||
self.nodes[0].sendrawtransaction(hexstring = raw_claim.serialize().hex())
|
||||
self.nodes[0].generate(1)
|
||||
last_blk = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
|
||||
raw_claim.rehash()
|
||||
assert(raw_claim.hash in last_blk['tx'])
|
||||
|
||||
def issuance_test(self, sighash_ty):
|
||||
tx, prev_vout, spk, sec, pub, tweak = self.create_taproot_utxo()
|
||||
|
||||
blind_addr = self.nodes[0].getnewaddress()
|
||||
nonblind_addr = self.nodes[0].validateaddress(blind_addr)['unconfidential']
|
||||
raw_tx = self.nodes[0].createrawtransaction([], {nonblind_addr: 1})
|
||||
raw_tx = FromHex(CTransaction(), raw_tx)
|
||||
|
||||
# Need to taproot outputs later because fundrawtransaction cannot estimate fees
|
||||
# prev out has value 1.2 btc
|
||||
in_total = tx.vout[prev_vout].nValue.getAmount()
|
||||
fees = 100
|
||||
raw_tx.vin.append(CTxIn(COutPoint(tx.sha256, prev_vout)))
|
||||
raw_tx.vout.append(CTxOut(nValue = CTxOutValue(in_total - fees - 10**8), scriptPubKey = spk)) # send back to self
|
||||
raw_tx.vout.append(CTxOut(nValue = CTxOutValue(fees)))
|
||||
|
||||
# issued_tx = raw_tx.serialize().hex()
|
||||
blind_addr = self.nodes[0].getnewaddress()
|
||||
issue_addr = self.nodes[0].validateaddress(blind_addr)['unconfidential']
|
||||
issued_tx = self.nodes[0].rawissueasset(raw_tx.serialize().hex(), [{"asset_amount":2, "asset_address":issue_addr, "blind":False}])[0]["hex"]
|
||||
# blind_tx = self.nodes[0].blindrawtransaction(issued_tx) # This is a no-op
|
||||
genesis_hash = uint256_from_str(bytes.fromhex(self.nodes[0].getblockhash(0))[::-1])
|
||||
issued_tx = FromHex(CTransaction(), issued_tx)
|
||||
issued_tx.wit.vtxoutwit = [CTxOutWitness()] * len(issued_tx.vout)
|
||||
issued_tx.wit.vtxinwit = [CTxInWitness()] * len(issued_tx.vin)
|
||||
msg = TaprootSignatureHash(issued_tx, [tx.vout[prev_vout]], sighash_ty, genesis_hash, 0)
|
||||
|
||||
# compute the tweak
|
||||
tweak_sk = tweak_add_privkey(sec, tweak)
|
||||
sig = sign_schnorr(tweak_sk, msg)
|
||||
issued_tx.wit.vtxinwit[0].scriptWitness.stack = [taproot_pad_sighash_ty(sig, sighash_ty)]
|
||||
pub_tweak = tweak_add_pubkey(pub, tweak)[0]
|
||||
assert(verify_schnorr(pub_tweak, sig, msg))
|
||||
# Since we add in/outputs the min feerate is no longer maintained.
|
||||
self.nodes[0].sendrawtransaction(hexstring = issued_tx.serialize().hex())
|
||||
self.nodes[0].generate(1)
|
||||
last_blk = self.nodes[0].getblock(self.nodes[0].getbestblockhash())
|
||||
issued_tx.rehash()
|
||||
assert(issued_tx.hash in last_blk['tx'])
|
||||
|
||||
|
||||
def run_test(self):
|
||||
self.nodes[0].generate(101)
|
||||
self.wait_until(lambda: self.nodes[0].getblockcount() == 101, timeout=5)
|
||||
self.log.info("Testing sighash taproot pegins")
|
||||
# Note that this does not test deposit to taproot pegin addresses
|
||||
# because there is no support for taproot pegins in rpc. The current rpc assumes
|
||||
# to shwsh tweaked address
|
||||
for sighash_ty in VALID_SIGHASHES_TAPROOT:
|
||||
self.pegin_test(sighash_ty)
|
||||
self.log.info("Testing sighash taproot issuances")
|
||||
for sighash_ty in VALID_SIGHASHES_TAPROOT:
|
||||
self.issuance_test(sighash_ty)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
TapHashPeginTest().main()
|
||||
|
|
@ -18,8 +18,8 @@ from test_framework.messages import (
|
|||
CTxIn,
|
||||
CTxInWitness,
|
||||
CTxOut,
|
||||
CTxOutValue,
|
||||
ToHex,
|
||||
CTxOutValue, CTxOutWitness,
|
||||
ToHex, uint256_from_str,
|
||||
)
|
||||
from test_framework.script import (
|
||||
ANNEX_TAG,
|
||||
|
|
@ -123,6 +123,11 @@ import random
|
|||
#
|
||||
# in that ctx3 will globally use hashtype=SIGHASH_DEFAULT (including in the hashtype byte appended to the signature)
|
||||
# while ctx2 only uses the modified hashtype inside the sighash calculation.
|
||||
#
|
||||
# ELEMENTS:
|
||||
# Elements taphash calculation also depends on genesis_block_hash which is stored as
|
||||
# `genesis_hash` in the test config
|
||||
g_genesis_hash = None
|
||||
|
||||
def deep_eval(ctx, expr):
|
||||
"""Recursively replace any callables c in expr (including inside lists) with c(ctx)."""
|
||||
|
|
@ -191,11 +196,13 @@ def default_controlblock(ctx):
|
|||
"""Default expression for "controlblock": combine leafversion, negflag, pubkey_inner, merklebranch."""
|
||||
return bytes([get(ctx, "leafversion") + get(ctx, "negflag")]) + get(ctx, "pubkey_inner") + get(ctx, "merklebranch")
|
||||
|
||||
#ELEMENTS: taphash depends on genesis hash
|
||||
def default_sighash(ctx):
|
||||
"""Default expression for "sighash": depending on mode, compute BIP341, BIP143, or legacy sighash."""
|
||||
tx = get(ctx, "tx")
|
||||
idx = get(ctx, "idx")
|
||||
hashtype = get(ctx, "hashtype_actual")
|
||||
genesis_hash = get(ctx, "genesis_hash")
|
||||
mode = get(ctx, "mode")
|
||||
if mode == "taproot":
|
||||
# BIP341 signature hash
|
||||
|
|
@ -205,9 +212,9 @@ def default_sighash(ctx):
|
|||
codeseppos = get(ctx, "codeseppos")
|
||||
leaf_ver = get(ctx, "leafversion")
|
||||
script = get(ctx, "script_taproot")
|
||||
return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
|
||||
return TaprootSignatureHash(tx, utxos, hashtype, genesis_hash, idx, scriptpath=True, script=script, leaf_ver=leaf_ver, codeseparator_pos=codeseppos, annex=annex)
|
||||
else:
|
||||
return TaprootSignatureHash(tx, utxos, hashtype, idx, scriptpath=False, annex=annex)
|
||||
return TaprootSignatureHash(tx, utxos, hashtype, genesis_hash, idx, scriptpath=False, annex=annex)
|
||||
elif mode == "witv0":
|
||||
# BIP143 signature hash
|
||||
scriptcode = get(ctx, "scriptcode")
|
||||
|
|
@ -373,6 +380,8 @@ DEFAULT_CONTEXT = {
|
|||
"leaf": None,
|
||||
# The input arguments to provide to the executed script
|
||||
"inputs": [],
|
||||
# Genesis hash(required for taproot outputs)
|
||||
"genesis_hash": None,
|
||||
|
||||
# == Parameters to be set before evaluation: ==
|
||||
# - mode: what spending style to use ("taproot", "witv0", or "legacy").
|
||||
|
|
@ -382,6 +391,7 @@ DEFAULT_CONTEXT = {
|
|||
# - utxos: the UTXOs being spent (needed in mode=="witv0" and mode=="taproot").
|
||||
# - idx: the input position being signed.
|
||||
# - scriptcode: the scriptcode to include in legacy and witv0 sighashes.
|
||||
# - genesisHash: The genesis hash of the block
|
||||
}
|
||||
|
||||
def flatten(lst):
|
||||
|
|
@ -433,7 +443,7 @@ def spend(tx, idx, utxos, **kwargs):
|
|||
|
||||
Spender = namedtuple("Spender", "script,comment,is_standard,sat_function,err_msg,sigops_weight,no_fail,need_vin_vout_mismatch")
|
||||
|
||||
def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, spk_mutate_pre_p2sh=None, failure=None, standard=True, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
|
||||
def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=False, genesis_hash=None, spk_mutate_pre_p2sh=None, failure=None, standard=True, err_msg=None, sigops_weight=0, need_vin_vout_mismatch=False, **kwargs):
|
||||
"""Helper for constructing Spender objects using the context signing framework.
|
||||
|
||||
* tap: a TaprootInfo object (see taproot_construct), for Taproot spends (cannot be combined with pkh, witv0, or script)
|
||||
|
|
@ -449,6 +459,10 @@ def make_spender(comment, *, tap=None, witv0=False, script=None, pkh=None, p2sh=
|
|||
"""
|
||||
|
||||
conf = dict()
|
||||
global g_genesis_hash
|
||||
if genesis_hash is None:
|
||||
genesis_hash = g_genesis_hash
|
||||
conf["genesis_hash"] = genesis_hash
|
||||
|
||||
# Compute scriptPubKey and set useful defaults based on the inputs.
|
||||
if witv0:
|
||||
|
|
@ -1216,7 +1230,6 @@ class TaprootTest(BitcoinTestFramework):
|
|||
extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))
|
||||
if extra_output_script == CScript():
|
||||
extra_output_script = None ## ELEMENTS: an explicitly empty coinbase scriptpubkey would be rejected with bad-cb-fee
|
||||
|
||||
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees), self.lastblocktime + 1)
|
||||
block.nVersion = 4
|
||||
for tx in txs:
|
||||
|
|
@ -1309,9 +1322,12 @@ class TaprootTest(BitcoinTestFramework):
|
|||
amount = int(random.randrange(int(avg*0.85 + 0.5), int(avg*1.15 + 0.5)) + 0.5)
|
||||
balance -= amount
|
||||
fund_tx.vout.append(CTxOut(amount, spenders[done + i].script))
|
||||
fund_tx.wit.vtxoutwit.append(CTxOutWitness())
|
||||
# Add change
|
||||
fund_tx.vout.append(CTxOut(balance - 10000, random.choice(host_spks)))
|
||||
fund_tx.wit.vtxoutwit.append(CTxOutWitness())
|
||||
fund_tx.vout.append(CTxOut(10000)) # ELEMENTS: and fee
|
||||
fund_tx.wit.vtxoutwit.append(CTxOutWitness())
|
||||
# Ask the wallet to sign
|
||||
ss = BytesIO(bytes.fromhex(node.signrawtransactionwithwallet(ToHex(fund_tx))["hex"]))
|
||||
fund_tx.deserialize(ss)
|
||||
|
|
@ -1387,6 +1403,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
assert in_value >= 0 and fee - num_outputs * DUST_LIMIT >= MIN_FEE
|
||||
for i in range(num_outputs):
|
||||
tx.vout.append(CTxOut())
|
||||
tx.wit.vtxoutwit.append(CTxOutWitness())
|
||||
if in_value <= DUST_LIMIT:
|
||||
tx.vout[-1].nValue = CTxOutValue(DUST_LIMIT)
|
||||
elif i < num_outputs - 1:
|
||||
|
|
@ -1399,6 +1416,7 @@ class TaprootTest(BitcoinTestFramework):
|
|||
fee += in_value
|
||||
assert fee >= 0
|
||||
tx.vout.append(CTxOut(fee))
|
||||
tx.wit.vtxoutwit.append(CTxOutWitness())
|
||||
|
||||
# Select coinbase pubkey
|
||||
cb_pubkey = random.choice(host_pubkeys)
|
||||
|
|
@ -1453,6 +1471,8 @@ class TaprootTest(BitcoinTestFramework):
|
|||
# Post-taproot activation tests go first (pre-taproot tests' blocks are invalid post-taproot).
|
||||
self.log.info("Post-activation tests...")
|
||||
self.nodes[1].generate(101)
|
||||
global g_genesis_hash
|
||||
g_genesis_hash = uint256_from_str(bytes.fromhex(self.nodes[1].getblockhash(0))[::-1])
|
||||
self.test_spenders(self.nodes[1], spenders_taproot_active(), input_counts=[1, 2, 2, 2, 2, 3])
|
||||
|
||||
# Transfer funds to pre-taproot node.
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ class CAssetIssuance():
|
|||
self.nAmount = CTxOutValue()
|
||||
self.nAmount.deserialize(f)
|
||||
self.nInflationKeys = CTxOutValue()
|
||||
self.nInflatoinKeys.deserialize(f)
|
||||
self.nInflationKeys.deserialize(f)
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
|
|
@ -405,6 +405,14 @@ class CAssetIssuance():
|
|||
r += self.nInflationKeys.serialize()
|
||||
return r
|
||||
|
||||
# serialization of asset issuance used in taproot sighash
|
||||
def taphash_asset_issuance_serialize(self):
|
||||
if self.isNull():
|
||||
return b'\x00'
|
||||
r = b''
|
||||
r += self.serialize()
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "CAssetIssuance(assetBlindingNonce=%064x assetEntropy=%064x nAmount=%s nInflationKeys=%s)" % (self.assetBlindingNonce, self.assetEntropy, self.nAmount.vchCommitment, self.nInflationKeys.vchCommitment)
|
||||
|
||||
|
|
@ -492,10 +500,10 @@ class CTxOutAsset:
|
|||
r += self.vchCommitment
|
||||
return r
|
||||
|
||||
#def setToAsset(self, val):
|
||||
# if len(val) != 32:
|
||||
# raise 'invalid asset hash (expected 32 bytes got %d)' % len(val)
|
||||
# self.vchCommitment = b'\x01' + val
|
||||
def setToAsset(self, val):
|
||||
if len(val) != 32:
|
||||
raise 'invalid asset hash (expected 32 bytes)'
|
||||
self.vchCommitment = b'\x01' + val
|
||||
|
||||
def __repr__(self):
|
||||
return "CTxOutAsset(vchCommitment=%s)" % self.vchCommitment
|
||||
|
|
@ -535,10 +543,15 @@ class CTxOutValue:
|
|||
return r
|
||||
|
||||
def setToAmount(self, amount):
|
||||
commit = [1]*9
|
||||
for i in range(8): #8 bytes
|
||||
commit[8-i] = ((amount >> (i*8)) & 0xff)
|
||||
self.vchCommitment = bytes(commit)
|
||||
if type(amount) == int:
|
||||
commit = [1]*9
|
||||
for i in range(8): #8 bytes
|
||||
commit[8-i] = ((amount >> (i*8)) & 0xff)
|
||||
self.vchCommitment = bytes(commit)
|
||||
else:
|
||||
if len(amount) != 8:
|
||||
raise 'invalid explicit amount (expected 8 bytes)'
|
||||
self.vchCommitment = b'\x01' + amount[::-1]
|
||||
|
||||
def getAmount(self):
|
||||
if self.vchCommitment[0] != 1:
|
||||
|
|
@ -621,6 +634,13 @@ class CTxOut():
|
|||
r += ser_string(self.scriptPubKey)
|
||||
return r
|
||||
|
||||
def from_pegin_witness_data(self, peg_witness):
|
||||
self.nAsset = CTxOutAsset()
|
||||
self.nAsset.setToAsset(peg_witness.stack[1])
|
||||
self.nValue = CTxOutValue()
|
||||
self.nValue.setToAmount(peg_witness.stack[0])
|
||||
self.scriptPubKey = peg_witness.stack[3]
|
||||
|
||||
def __repr__(self):
|
||||
return "CTxOut(nAsset=%s nValue=%s nNonce=%s scriptPubKey=%s)" \
|
||||
% (self.nAsset, self.nValue, self.nNonce, self.scriptPubKey.hex())
|
||||
|
|
@ -667,6 +687,13 @@ class CTxInWitness:
|
|||
r += ser_string_vector(self.peginWitness.stack)
|
||||
return r
|
||||
|
||||
# Used in taproot sighash calculation
|
||||
def serialize_issuance_proofs(self):
|
||||
r = b''
|
||||
r += ser_string(self.vchIssuanceAmountRangeproof)
|
||||
r += ser_string(self.vchInflationKeysRangeproof)
|
||||
return r
|
||||
|
||||
def calc_witness_hash(self):
|
||||
leaves = [
|
||||
encode(hash256(ser_string(self.vchIssuanceAmountRangeproof))[::-1], 'hex_codec').decode('ascii'),
|
||||
|
|
|
|||
|
|
@ -608,6 +608,15 @@ SIGHASH_ANYONECANPAY = 0x80
|
|||
# ELEMENTS:
|
||||
SIGHASH_RANGEPROOF = 0x40
|
||||
|
||||
# Add the sighash byte to the signature(Taproot sigs only)
|
||||
# Nothing is padded if sighash is default
|
||||
def taproot_pad_sighash_ty(sig, sighash_ty):
|
||||
if len(sig) != 64:
|
||||
raise "Schnorr sigs must be 64 bytes"
|
||||
if sighash_ty != SIGHASH_DEFAULT:
|
||||
sig = sig + bytes([sighash_ty])
|
||||
return sig
|
||||
|
||||
def FindAndDelete(script, sig):
|
||||
"""Consensus critical, see FindAndDelete() in Satoshi codebase"""
|
||||
r = b''
|
||||
|
|
@ -793,35 +802,48 @@ class TestFrameworkScript(unittest.TestCase):
|
|||
for value in values:
|
||||
self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value)
|
||||
|
||||
def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
|
||||
def TaprootSignatureHash(txTo, spent_utxos, hash_type, genesis_hash, input_index = 0, scriptpath = False, script = CScript(), codeseparator_pos = -1, annex = None, leaf_ver = LEAF_VERSION_TAPSCRIPT):
|
||||
assert (len(txTo.vin) == len(spent_utxos))
|
||||
assert (input_index < len(txTo.vin))
|
||||
out_type = SIGHASH_ALL if hash_type == 0 else hash_type & 3
|
||||
in_type = hash_type & SIGHASH_ANYONECANPAY
|
||||
spk = spent_utxos[input_index].scriptPubKey
|
||||
ss = bytes([0, hash_type]) # epoch, hash_type
|
||||
ss = b""
|
||||
ss += ser_uint256(genesis_hash)
|
||||
ss += ser_uint256(genesis_hash)
|
||||
ss += bytes([hash_type]) # hash_type
|
||||
ss += struct.pack("<i", txTo.nVersion)
|
||||
ss += struct.pack("<I", txTo.nLockTime)
|
||||
if in_type != SIGHASH_ANYONECANPAY:
|
||||
ss += sha256(b"".join(struct.pack("B", ((not i.assetIssuance.isNull()) << 7) + (i.m_is_pegin << 6)) for i in txTo.vin))
|
||||
ss += sha256(b"".join(i.prevout.serialize() for i in txTo.vin))
|
||||
ss += sha256(b"".join(u.nValue.serialize() for u in spent_utxos))
|
||||
ss += sha256(b"".join(u.nAsset.serialize() + u.nValue.serialize() for u in spent_utxos))
|
||||
ss += sha256(b"".join(ser_string(u.scriptPubKey) for u in spent_utxos))
|
||||
ss += sha256(b"".join(struct.pack("<I", i.nSequence) for i in txTo.vin))
|
||||
ss += sha256(b"".join(i.assetIssuance.taphash_asset_issuance_serialize() for i in txTo.vin))
|
||||
ss += sha256(b"".join(iwit.serialize_issuance_proofs() for iwit in txTo.wit.vtxinwit))
|
||||
if out_type == SIGHASH_ALL:
|
||||
ss += sha256(b"".join(o.serialize() for o in txTo.vout))
|
||||
ss += sha256(b"".join(owit.serialize() for owit in txTo.wit.vtxoutwit))
|
||||
spend_type = 0
|
||||
if annex is not None:
|
||||
spend_type |= 1
|
||||
if (scriptpath):
|
||||
spend_type |= 2
|
||||
ss += bytes([spend_type])
|
||||
|
||||
if in_type == SIGHASH_ANYONECANPAY:
|
||||
ss += struct.pack("B", ((not txTo.vin[input_index].assetIssuance.isNull()) << 7) + (txTo.vin[input_index].m_is_pegin << 6))
|
||||
ss += txTo.vin[input_index].prevout.serialize()
|
||||
ss += spent_utxos[input_index].nAsset.serialize()
|
||||
ss += spent_utxos[input_index].nValue.serialize()
|
||||
ss += spent_utxos[input_index].nNonce.serialize()
|
||||
ss += ser_string(spk)
|
||||
ss += struct.pack("<I", txTo.vin[input_index].nSequence)
|
||||
if txTo.vin[input_index].assetIssuance.isNull():
|
||||
ss += b'\x00'
|
||||
else:
|
||||
ss += txTo.vin[input_index].assetIssuance.serialize()
|
||||
ss += sha256(txTo.wit.vtxinwit[input_index].serialize_issuance_proofs())
|
||||
else:
|
||||
ss += struct.pack("<I", input_index)
|
||||
if (spend_type & 1):
|
||||
|
|
@ -829,15 +851,25 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
|
|||
if out_type == SIGHASH_SINGLE:
|
||||
if input_index < len(txTo.vout):
|
||||
ss += sha256(txTo.vout[input_index].serialize())
|
||||
ss += sha256(txTo.wit.vtxoutwit[input_index].serialize())
|
||||
else:
|
||||
# Why do we have a case for in > len ?
|
||||
# Maybe useful in testing. C++ code should never reach here
|
||||
ss += bytes(0 for _ in range(32))
|
||||
ss += bytes(0 for _ in range(32))
|
||||
if (scriptpath):
|
||||
ss += TaggedHash("TapLeaf", bytes([leaf_ver]) + ser_string(script))
|
||||
ss += TaggedHash("TapLeaf/elements", bytes([leaf_ver]) + ser_string(script))
|
||||
ss += bytes([0])
|
||||
ss += struct.pack("<i", codeseparator_pos)
|
||||
# ELEMENTS -35 since we encode nAsset (33) + nValue (9) + nNonce (1) rather than nValue (8)
|
||||
assert len(ss) == 175 - (in_type == SIGHASH_ANYONECANPAY) * (49 - 35) - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 32 + (annex is not None) * 32 + scriptpath * 37
|
||||
return TaggedHash("TapSighash", ss)
|
||||
exp_non_acp_len = 366 - (out_type != SIGHASH_ALL and out_type != SIGHASH_SINGLE) * 64 + (annex is not None) * 32 + scriptpath * 37
|
||||
if in_type != SIGHASH_ANYONECANPAY:
|
||||
assert len(ss) == exp_non_acp_len
|
||||
else:
|
||||
# 119 when explicit outs with no issuance. 304 when when conf tx with conf issuances.
|
||||
assert len(ss) >= exp_non_acp_len - (228 - 119)
|
||||
assert len(ss) <= exp_non_acp_len - (228 - 304)
|
||||
return TaggedHash("TapSighash/elements", ss)
|
||||
|
||||
def taproot_tree_helper(scripts):
|
||||
if len(scripts) == 0:
|
||||
|
|
@ -856,7 +888,7 @@ def taproot_tree_helper(scripts):
|
|||
version = script[2]
|
||||
assert version & 1 == 0
|
||||
assert isinstance(code, bytes)
|
||||
h = TaggedHash("TapLeaf", bytes([version]) + ser_string(code))
|
||||
h = TaggedHash("TapLeaf/elements", bytes([version]) + ser_string(code))
|
||||
if name is None:
|
||||
return ([], h)
|
||||
return ([(name, version, code, bytes())], h)
|
||||
|
|
@ -875,7 +907,7 @@ def taproot_tree_helper(scripts):
|
|||
right = [(name, version, script, control + left_h) for name, version, script, control in right]
|
||||
if right_h < left_h:
|
||||
right_h, left_h = left_h, right_h
|
||||
h = TaggedHash("TapBranch", left_h + right_h)
|
||||
h = TaggedHash("TapBranch/elements", left_h + right_h)
|
||||
return (left + right, h)
|
||||
|
||||
TaprootInfo = namedtuple("TaprootInfo", "scriptPubKey,inner_pubkey,negflag,tweak,leaves")
|
||||
|
|
@ -898,10 +930,10 @@ def taproot_construct(pubkey, scripts=None):
|
|||
scripts = []
|
||||
|
||||
ret, h = taproot_tree_helper(scripts)
|
||||
tweak = TaggedHash("TapTweak", pubkey + h)
|
||||
tweak = TaggedHash("TapTweak/elements", pubkey + h)
|
||||
tweaked, negated = tweak_add_pubkey(pubkey, tweak)
|
||||
leaves = dict((name, TaprootLeafInfo(script, version, merklebranch)) for name, version, script, merklebranch in ret)
|
||||
return TaprootInfo(CScript([OP_1, tweaked]), pubkey, negated + 0, tweak, leaves)
|
||||
|
||||
def is_op_success(o):
|
||||
return o == 0x50 or o == 0x62 or o == 0x89 or o == 0x8a or o == 0x8d or o == 0x8e or (o >= 0x7e and o <= 0x81) or (o >= 0x83 and o <= 0x86) or (o >= 0x95 and o <= 0x99) or (o >= 0xbb and o <= 0xfe)
|
||||
return o == 80 or o == 98 or (o >= 137 and o <= 138) or (o >= 141 and o <= 142) or (o >= 149 and o <= 151) or (o >= 187 and o <= 191) or (o >= 196 and o <= 254)
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ BASE_SCRIPTS = [
|
|||
'wallet_listtransactions.py',
|
||||
'wallet_listtransactions.py --descriptors',
|
||||
'feature_taproot.py',
|
||||
'feature_taphash_pegins_issuances.py',
|
||||
# vv Tests less than 60s vv
|
||||
'p2p_sendheaders.py',
|
||||
'wallet_importmulti.py --legacy-wallet',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue