mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
remove legacy peg-in/withdrawlocks
This commit is contained in:
parent
b2bbc67e9c
commit
65ed777e6e
42 changed files with 178 additions and 1793 deletions
|
|
@ -1,232 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from test_framework.authproxy import AuthServiceProxy, JSONRPCException
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
import subprocess
|
||||
import shutil
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("paths to bitcoind and sidechain daemon must be included as arguments")
|
||||
sys.exit(0)
|
||||
print(sys.argv[1])
|
||||
print(sys.argv[2])
|
||||
|
||||
fedpeg_key="cPxqWyf1HDGpGFH1dnfjz8HbiWxvwG8WXyetbuAiw4thKXUdXLpR"
|
||||
fedpeg_pubkey="512103dff4923d778550cc13ce0d887d737553b4b58f4e8e886507fc39f5e447b2186451ae"
|
||||
|
||||
bitcoin_datadir="/tmp/"+''.join(random.choice('0123456789ABCDEF') for i in range(5))
|
||||
bitcoin_pass=''.join(random.choice('0123456789ABCDEF') for i in range(10))
|
||||
sidechain_datadir="/tmp/"+''.join(random.choice('0123456789ABCDEF') for i in range(5))
|
||||
sidechain_pass=''.join(random.choice('0123456789ABCDEF') for i in range(10))
|
||||
sidechain2_datadir="/tmp/"+''.join(random.choice('0123456789ABCDEF') for i in range(5))
|
||||
sidechain2_pass=''.join(random.choice('0123456789ABCDEF') for i in range(10))
|
||||
|
||||
bitcoin_port = 8000 + os.getpid()%999
|
||||
sidechain_port = bitcoin_port + 1
|
||||
sidechain2_port = bitcoin_port + 2
|
||||
sidechain1_p2p_port = bitcoin_port + 3
|
||||
sidechain2_p2p_port = bitcoin_port + 4
|
||||
|
||||
os.makedirs(bitcoin_datadir)
|
||||
os.makedirs(sidechain_datadir)
|
||||
os.makedirs(sidechain2_datadir)
|
||||
|
||||
with open(os.path.join(bitcoin_datadir, "bitcoin.conf"), 'w') as f:
|
||||
f.write("regtest=1\n")
|
||||
f.write("rpcuser=bitcoinrpc\n")
|
||||
f.write("rpcpassword="+bitcoin_pass+"\n")
|
||||
f.write("rpcport="+str(bitcoin_port)+"\n")
|
||||
f.write("discover=0\n")
|
||||
f.write("listen=0\n")
|
||||
f.write("testnet=0\n")
|
||||
f.write("txindex=1\n")
|
||||
f.write("daemon=1\n")
|
||||
f.write("listen=0\n")
|
||||
|
||||
with open(os.path.join(sidechain_datadir, "elements.conf"), 'w') as f:
|
||||
f.write("regtest=1\n")
|
||||
f.write("rpcuser=sidechainrpc\n")
|
||||
f.write("rpcpassword="+sidechain_pass+"\n")
|
||||
f.write("rpcport="+str(sidechain_port)+"\n")
|
||||
f.write("discover=0\n")
|
||||
f.write("testnet=0\n")
|
||||
f.write("txindex=1\n")
|
||||
f.write("fedpegscript="+fedpeg_pubkey+"\n")
|
||||
f.write("daemon=1\n")
|
||||
f.write("mainchainrpchost=127.0.0.1\n")
|
||||
f.write("mainchainrpcport="+str(bitcoin_port)+"\n")
|
||||
f.write("mainchainrpcuser=bitcoinrpc\n")
|
||||
f.write("mainchainrpcpassword="+bitcoin_pass+"\n")
|
||||
f.write("validatepegin=1\n")
|
||||
f.write("validatepegout=0\n")
|
||||
f.write("port="+str(sidechain1_p2p_port)+"\n")
|
||||
f.write("connect=localhost:"+str(sidechain2_p2p_port)+"\n")
|
||||
f.write("listen=1\n")
|
||||
|
||||
with open(os.path.join(sidechain2_datadir, "elements.conf"), 'w') as f:
|
||||
f.write("regtest=1\n")
|
||||
f.write("rpcuser=sidechainrpc2\n")
|
||||
f.write("rpcpassword="+sidechain2_pass+"\n")
|
||||
f.write("rpcport="+str(sidechain2_port)+"\n")
|
||||
f.write("discover=0\n")
|
||||
f.write("testnet=0\n")
|
||||
f.write("txindex=1\n")
|
||||
f.write("fedpegscript="+fedpeg_pubkey+"\n")
|
||||
f.write("daemon=1\n")
|
||||
f.write("mainchainrpchost=127.0.0.1\n")
|
||||
f.write("mainchainrpcport="+str(bitcoin_port)+"\n")
|
||||
f.write("mainchainrpcuser=bitcoinrpc\n")
|
||||
f.write("mainchainrpcpassword="+bitcoin_pass+"\n")
|
||||
f.write("validatepegin=1\n")
|
||||
f.write("validatepegout=0\n")
|
||||
f.write("port="+str(sidechain2_p2p_port)+"\n")
|
||||
f.write("connect=localhost:"+str(sidechain1_p2p_port)+"\n")
|
||||
f.write("listen=1\n")
|
||||
|
||||
try:
|
||||
|
||||
# Default is 8, meaning 8+2 confirms for mempool acceptance normally
|
||||
# this will require 10+2.
|
||||
sidechain_args = " -peginconfirmationdepth=10 "
|
||||
|
||||
# Start daemons
|
||||
print("Starting daemons at "+bitcoin_datadir+", "+sidechain_datadir+" and "+sidechain2_datadir)
|
||||
bitcoindstart = sys.argv[1]+"/bitcoind -datadir="+bitcoin_datadir
|
||||
subprocess.Popen(bitcoindstart.split(), stdout=subprocess.PIPE)
|
||||
|
||||
sidechainstart = sys.argv[2]+"/elementsd -datadir="+sidechain_datadir + sidechain_args
|
||||
subprocess.Popen(sidechainstart.split(), stdout=subprocess.PIPE)
|
||||
|
||||
sidechain2start = sys.argv[2]+"/elementsd -datadir="+sidechain2_datadir + sidechain_args
|
||||
subprocess.Popen(sidechain2start.split(), stdout=subprocess.PIPE)
|
||||
|
||||
print("Daemons started")
|
||||
time.sleep(3)
|
||||
|
||||
bitcoin = AuthServiceProxy("http://bitcoinrpc:"+bitcoin_pass+"@127.0.0.1:"+str(bitcoin_port))
|
||||
sidechain = AuthServiceProxy("http://sidechainrpc:"+sidechain_pass+"@127.0.0.1:"+str(sidechain_port))
|
||||
sidechain2 = AuthServiceProxy("http://sidechainrpc2:"+sidechain2_pass+"@127.0.0.1:"+str(sidechain2_port))
|
||||
print("Daemons started, making blocks to get funds")
|
||||
|
||||
bitcoin.generate(101)
|
||||
sidechain.generate(101)
|
||||
|
||||
addr = bitcoin.getnewaddress()
|
||||
|
||||
# Lockup some funds to unlock later
|
||||
sidechain.sendtomainchain(addr, 50)
|
||||
# Tests withdrawlock tracking in database
|
||||
sidechain.generate(1)
|
||||
# Tests withdrawlock in mempool
|
||||
sidechain.sendtomainchain(addr, 50)
|
||||
|
||||
addrs = sidechain.getpeginaddress()
|
||||
txid1 = bitcoin.sendtoaddress(addrs["mainchain_address"], 24)
|
||||
txid2 = bitcoin.sendtoaddress(addrs["mainchain_address"], 24)
|
||||
# 10+2 confirms required to get into mempool and confirm
|
||||
bitcoin.generate(11)
|
||||
time.sleep(2)
|
||||
proof = bitcoin.gettxoutproof([txid1])
|
||||
raw = bitcoin.getrawtransaction(txid1)
|
||||
|
||||
print("Attempting peg-in")
|
||||
try:
|
||||
pegtxid = sidechain.claimpegin(raw, proof)
|
||||
raise Exception("Peg-in should not mature enough yet, need another block.")
|
||||
except JSONRPCException as e:
|
||||
assert("Withdraw proof validation failed" in e.error["message"])
|
||||
pass
|
||||
|
||||
# Should fail due to non-matching wallet address
|
||||
try:
|
||||
pegtxid = sidechain.claimpegin(raw, proof, sidechain.getnewaddress())
|
||||
raise Exception("Peg-in with non-matching address should fail.")
|
||||
except JSONRPCException as e:
|
||||
assert("Failed to find output in bitcoinTx to the mainchain_address" in e.error["message"])
|
||||
pass
|
||||
|
||||
# 12 confirms allows in mempool
|
||||
bitcoin.generate(1)
|
||||
|
||||
timeout = 20
|
||||
# Both should succeed via wallet lookup for address match, and when given
|
||||
pegtxid1 = sidechain.claimpegin(raw, proof)
|
||||
|
||||
proof = bitcoin.gettxoutproof([txid2])
|
||||
raw = bitcoin.getrawtransaction(txid2)
|
||||
pegtxid2 = sidechain.claimpegin(raw, proof, addrs["sidechain_address"])
|
||||
|
||||
while len(sidechain.getrawmempool()) != len(sidechain2.getrawmempool()):
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
if timeout == 0:
|
||||
raise Exception("Peg-in has failed to propagate.")
|
||||
sidechain2.generate(1)
|
||||
while sidechain.getblockcount() != sidechain2.getblockcount():
|
||||
time.sleep(1)
|
||||
timeout -= 1
|
||||
if timeout == 0:
|
||||
raise Exception("Blocks are not propagating.")
|
||||
|
||||
|
||||
tx1 = sidechain.gettransaction(pegtxid1)
|
||||
tx2 = sidechain.gettransaction(pegtxid2)
|
||||
|
||||
if "confirmations" in tx1 and tx1["confirmations"] > 0 and "confirmations" in tx2 and tx2["confirmations"] > 0:
|
||||
print("Peg-in is confirmed: Success!")
|
||||
else:
|
||||
raise Exception("Peg-in confirmation has failed.")
|
||||
|
||||
# Make a few large locks, then do many claims in mempool
|
||||
n_locks = 10
|
||||
n_claims = 30
|
||||
|
||||
print("Flooding mempool with many small claims")
|
||||
pegtxs = []
|
||||
for i in range(n_locks):
|
||||
# Lockup some funds to unlock later
|
||||
sidechain.sendtomainchain(addr, 50)
|
||||
sidechain.generate(1)
|
||||
sidechain.generate(101)
|
||||
|
||||
for i in range(n_claims):
|
||||
addrs = sidechain.getpeginaddress()
|
||||
txid = bitcoin.sendtoaddress(addrs["mainchain_address"], 1)
|
||||
bitcoin.generate(12)
|
||||
proof = bitcoin.gettxoutproof([txid])
|
||||
raw = bitcoin.getrawtransaction(txid)
|
||||
pegtxs += [sidechain.claimpegin(raw, proof)]
|
||||
|
||||
sidechain.generate(1)
|
||||
for pegtxid in pegtxs:
|
||||
tx = sidechain.gettransaction(pegtxid)
|
||||
if "confirmations" not in tx or tx["confirmations"] == 0:
|
||||
raise Exception("Peg-in confirmation has failed.")
|
||||
|
||||
print("Success!")
|
||||
|
||||
# Testing sidechain info RPC
|
||||
sideinfo = sidechain.getsidechaininfo()
|
||||
assert sideinfo["fedpegscript"] == fedpeg_pubkey
|
||||
assert sideinfo["pegged_asset"] == sidechain.dumpassetlabels()["bitcoin"]
|
||||
assert sideinfo["min_peg_diff"] == "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
assert sideinfo["parent_blockhash"] == "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"
|
||||
|
||||
except JSONRPCException as e:
|
||||
print("Pegging testing failed, aborting:")
|
||||
print(e.error)
|
||||
except Exception as e:
|
||||
print("Pegging testing failed, aborting:")
|
||||
print(e)
|
||||
|
||||
print("Stopping daemons and cleaning up")
|
||||
bitcoin.stop()
|
||||
sidechain.stop()
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
shutil.rmtree(sidechain_datadir)
|
||||
shutil.rmtree(bitcoin_datadir)
|
||||
|
|
@ -458,7 +458,7 @@ endif
|
|||
|
||||
libelementsconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0 $(RELDFLAGS)
|
||||
libelementsconsensus_la_LIBADD = $(LIBSECP256K1)
|
||||
libelementsconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -DBITCOIN_SCRIPT_NO_CALLRPC
|
||||
libelementsconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
|
||||
libelementsconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ BITCOIN_TESTS =\
|
|||
test/hash_tests.cpp \
|
||||
test/key_tests.cpp \
|
||||
test/limitedmap_tests.cpp \
|
||||
test/lockedutxo_tests.cpp \
|
||||
test/withdrawspent_tests.cpp \
|
||||
test/dbwrapper_tests.cpp \
|
||||
test/main_tests.cpp \
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
|
|||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
|
||||
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
|
||||
0, spendsCoinbase, sigOpCost, lp, setWithdrawsSpent));
|
||||
0, spendsCoinbase, sigOpCost, lp, setPeginsSpent));
|
||||
}
|
||||
|
||||
// Right now this is only testing eviction performance in an extremely small
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ static void VerifyScriptBench(benchmark::State& state)
|
|||
txCredit.vout[0].scriptPubKey,
|
||||
&txSpend.wit.vtxinwit[0].scriptWitness,
|
||||
flags,
|
||||
MutableTransactionNoWithdrawsSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
|
||||
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
|
||||
&err);
|
||||
assert(err == SCRIPT_ERR_OK);
|
||||
assert(success);
|
||||
|
|
|
|||
|
|
@ -701,10 +701,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
|||
|
||||
// ... and merge in other signatures:
|
||||
BOOST_FOREACH(const CTransaction& txv, txVariants)
|
||||
sigdata = CombineSignatures(prevPubKey, MutableTransactionNoWithdrawsSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
|
||||
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
|
||||
UpdateTransaction(mergedTx, i, sigdata);
|
||||
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, (mergedTx.wit.vtxinwit.size() > i) ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionNoWithdrawsSignatureChecker(&mergedTx, i, amount)))
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, (mergedTx.wit.vtxinwit.size() > i) ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount)))
|
||||
fComplete = false;
|
||||
}
|
||||
|
||||
|
|
@ -716,58 +716,6 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
|
|||
tx = mergedTx;
|
||||
}
|
||||
|
||||
static void MutateTxPeginSign(CMutableTransaction& tx, const std::string& flagStr)
|
||||
{
|
||||
if (!registers.count("peginkeys"))
|
||||
throw std::runtime_error("peginkeys register variable must be set.");
|
||||
UniValue keysObj = registers["peginkeys"];
|
||||
|
||||
if (!keysObj.isObject())
|
||||
throw std::runtime_error("peginkeysObjs must be an object");
|
||||
std::map<std::string,UniValue::VType> types = boost::assign::map_list_of("contract",UniValue::VSTR)("txoutproof",UniValue::VSTR)("tx",UniValue::VSTR)("nout",UniValue::VNUM);
|
||||
if (!keysObj.checkObject(types))
|
||||
throw std::runtime_error("peginkeysObjs internal object typecheck fail");
|
||||
|
||||
std::vector<unsigned char> contractData(ParseHexUV(keysObj["contract"], "contract"));
|
||||
std::vector<unsigned char> txoutproofData(ParseHexUV(keysObj["txoutproof"], "txoutproof"));
|
||||
std::vector<unsigned char> txData(ParseHexUV(keysObj["tx"], "tx"));
|
||||
int nOut = atoi(keysObj["nout"].getValStr());
|
||||
|
||||
if (contractData.size() != 40)
|
||||
throw std::runtime_error("contract must be 40 bytes");
|
||||
|
||||
CDataStream ssProof(txoutproofData,SER_NETWORK, PROTOCOL_VERSION);
|
||||
Sidechain::Bitcoin::CMerkleBlock merkleBlock;
|
||||
ssProof >> merkleBlock;
|
||||
|
||||
CDataStream ssTx(txData, SER_NETWORK, PROTOCOL_VERSION);
|
||||
Sidechain::Bitcoin::CTransactionRef txBTCRef;
|
||||
ssTx >> txBTCRef;
|
||||
Sidechain::Bitcoin::CTransaction txBTC(*txBTCRef);
|
||||
|
||||
std::vector<uint256> transactionHashes;
|
||||
std::vector<unsigned int> transactionIndices;
|
||||
if (!CheckBitcoinProof(merkleBlock.header.GetHash(), merkleBlock.header.nBits) ||
|
||||
merkleBlock.txn.ExtractMatches(transactionHashes, transactionIndices) != merkleBlock.header.hashMerkleRoot ||
|
||||
transactionHashes.size() != 1 ||
|
||||
transactionHashes[0] != txBTC.GetHash())
|
||||
throw std::runtime_error("txoutproof is invalid or did not match tx");
|
||||
|
||||
if (nOut < 0 || (unsigned int) nOut >= txBTC.vout.size())
|
||||
throw std::runtime_error("nout must be >= 0, < txout count");
|
||||
|
||||
CScript scriptSig;
|
||||
scriptSig << contractData;
|
||||
scriptSig.PushWithdraw(txoutproofData);
|
||||
scriptSig.PushWithdraw(txData);
|
||||
scriptSig << nOut;
|
||||
|
||||
//TODO: Verify the withdraw proof
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
tx.vin[i].scriptSig = scriptSig;
|
||||
}
|
||||
}
|
||||
|
||||
class Secp256k1Init
|
||||
{
|
||||
ECCVerifyHandle globalVerifyHandle;
|
||||
|
|
@ -815,17 +763,13 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
|
|||
} else if (command == "blind") {
|
||||
if (!ecc) { ecc.reset(new Secp256k1Init()); }
|
||||
MutateTxBlind(tx, commandVal);
|
||||
} else if (command == "peginsign")
|
||||
MutateTxPeginSign(tx, commandVal);
|
||||
|
||||
else if (command == "load")
|
||||
} else if (command == "load") {
|
||||
RegisterLoad(commandVal);
|
||||
|
||||
else if (command == "set")
|
||||
} else if (command == "set") {
|
||||
RegisterSet(commandVal);
|
||||
|
||||
else
|
||||
} else {
|
||||
throw std::runtime_error("unknown command");
|
||||
}
|
||||
}
|
||||
|
||||
static void OutputTxJSON(const CTransaction& tx)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ static const unsigned char REJECT_NONSTANDARD = 0x40;
|
|||
static const unsigned char REJECT_DUST = 0x41;
|
||||
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
|
||||
static const unsigned char REJECT_CHECKPOINT = 0x43;
|
||||
static const unsigned char REJECT_SCRIPT = 0x44;
|
||||
|
||||
/** Capture information about block/transaction validation */
|
||||
class CValidationState {
|
||||
|
|
|
|||
|
|
@ -122,15 +122,6 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
{
|
||||
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
|
||||
|
||||
if (prev.scriptPubKey.IsWithdrawLock()) {
|
||||
if (!tx.vin[i].scriptSig.IsWithdrawProof()) {
|
||||
if (tx.vout.size() < i)
|
||||
if (!tx.vout[i].nValue.IsExplicit() || tx.vout[i].nValue.GetAmount() > MAX_MONEY / 100)
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
|
||||
// keys. (remember the 520 byte limit on redeemScript size) That works
|
||||
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
|
||||
|
|
|
|||
|
|
@ -68,8 +68,7 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
|
|||
SCRIPT_VERIFY_LOW_S |
|
||||
SCRIPT_VERIFY_WITNESS |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
|
||||
SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED;
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
|
||||
|
||||
/** For convenience, standard but not mandatory verify flags. */
|
||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
|||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
static const CFeeRate withdrawLockTxFee = CFeeRate(5460);
|
||||
|
||||
/**
|
||||
* Confidential assets, values, and nonces all share enough code in common
|
||||
* that it makes sense to define a common abstract base class. */
|
||||
|
|
@ -226,10 +224,6 @@ public:
|
|||
return false;
|
||||
if (IsFee())
|
||||
return false;
|
||||
//Withdrawlocks are evaluated at a higher, static feerate
|
||||
//to ensure peg-outs are IsStandard on mainchain
|
||||
if (scriptPubKey.IsWithdrawLock() && nValue.GetAmount() < GetDustThreshold(withdrawLockTxFee))
|
||||
return true;
|
||||
return (nValue.GetAmount() < GetDustThreshold(minRelayTxFee));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1388,14 +1388,14 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
|
|||
// ... and merge in other signatures:
|
||||
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
|
||||
if (txv.vin.size() > i) {
|
||||
sigdata = CombineSignatures(prevPubKey, TransactionNoWithdrawsSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
|
||||
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i));
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTransaction(mergedTx, i, sigdata);
|
||||
|
||||
ScriptError serror = SCRIPT_ERR_OK;
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, (mergedTx.wit.vtxinwit.size() > i) ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionNoWithdrawsSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
if (!VerifyScript(txin.scriptSig, prevPubKey, (mergedTx.wit.vtxinwit.size() > i) ? &mergedTx.wit.vtxinwit[i].scriptWitness : NULL, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
|
||||
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ static bool verify_flags(unsigned int flags)
|
|||
}
|
||||
|
||||
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CConfidentialValue amount,
|
||||
CConfidentialValue amountPreviousInput,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
|
||||
{
|
||||
|
|
@ -96,10 +95,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
|
|||
set_error(err, bitcoinconsensus_ERR_OK);
|
||||
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (amountPreviousInput.IsExplicit() && (amountPreviousInput.GetAmount() < -1 || (nIn != 0 && !MoneyRange(amountPreviousInput.GetAmount()))))
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), (tx.wit.vtxinwit.size() > nIn) ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionNoWithdrawsSignatureChecker(&tx, nIn, amount, txdata), NULL);
|
||||
else
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), (tx.wit.vtxinwit.size() > nIn) ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, amountPreviousInput, txdata, CScript()), NULL);
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), (tx.wit.vtxinwit.size() > nIn) ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
|
|
@ -120,7 +116,7 @@ int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey
|
|||
CConfidentialValue prevInAm;
|
||||
stream >> prevInAm;
|
||||
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, prevInAm, txTo, txToLen, nIn, flags, err);
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
|
|
@ -137,7 +133,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i
|
|||
|
||||
CConfidentialValue am(0);
|
||||
CConfidentialValue prevInAm(-2);
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, prevInAm, txTo, txToLen, nIn, flags, err);
|
||||
return ::verify_script(scriptPubKey, scriptPubKeyLen, am, txTo, txToLen, nIn, flags, err);
|
||||
}
|
||||
|
||||
unsigned int bitcoinconsensus_version()
|
||||
|
|
|
|||
|
|
@ -71,10 +71,8 @@ EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubK
|
|||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
|
||||
|
||||
// Use -1 for amountPreviousInput if there is no previous input (ie nIn == 0)
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script_with_amount(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char* amount, unsigned int amountLen,
|
||||
const unsigned char* amountPreviousInput, unsigned int amountPreviousInputLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@
|
|||
#include "utilstrencodings.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_NO_CALLRPC
|
||||
#include "callrpc.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
|
@ -272,26 +268,6 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool static WithdrawProofReadStackItem(const vector<valtype>& stack, const bool fRequireMinimal, int *stackOffset, valtype& read)
|
||||
{
|
||||
if (stack.size() < size_t(-(*stackOffset)))
|
||||
return false;
|
||||
int pushCount = CScriptNum(stacktop(*stackOffset), fRequireMinimal).getint();
|
||||
if (pushCount < 0 || pushCount > 2000 || stack.size() < size_t(-(*stackOffset) + pushCount))
|
||||
return false;
|
||||
(*stackOffset)--;
|
||||
|
||||
read.reserve(pushCount > 1 ? pushCount * 520 : 0);
|
||||
for (int i = pushCount - 1; i >= 0; i--) {
|
||||
if (i != 0 && stacktop((*stackOffset) - i).size() != 520)
|
||||
return false;
|
||||
const valtype& stackElem = stacktop((*stackOffset) - i);
|
||||
read.insert(read.end(), stackElem.begin(), stackElem.end());
|
||||
}
|
||||
(*stackOffset) -= pushCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||
{
|
||||
static const CScriptNum bnZero(0);
|
||||
|
|
@ -1417,182 +1393,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
|||
}
|
||||
break;
|
||||
|
||||
case OP_WITHDRAWPROOFVERIFY:
|
||||
{
|
||||
// In the make-withdraw case, reads the following from the stack:
|
||||
// 1. genesis block hash of the chain the withdraw is coming from
|
||||
// 2. the index within the locking tx's outputs we are claiming
|
||||
// 3. the locking tx itself (WithdrawProofReadStackItem)
|
||||
// 4. the merkle block structure which contains the block in which
|
||||
// the locking transaction is present (WithdrawProofReadStackItem)
|
||||
// 5. The contract which we are expected to send coins to
|
||||
//
|
||||
// In the combine-outputs case, reads the following from the stack:
|
||||
// 1. genesis block hash of the chain the withdraw is coming from
|
||||
|
||||
if (flags & SCRIPT_VERIFY_WITHDRAW) {
|
||||
if (stack.size() < 7 && stack.size() != 1)
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
const valtype &vgenesisHash = stacktop(-1);
|
||||
if (vgenesisHash.size() != 32)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT);
|
||||
|
||||
assert(checker.GetValueIn() != CConfidentialValue(-1)); // Not using a NoWithdrawSignatureChecker
|
||||
|
||||
CScript relockScript = CScript() << vgenesisHash << OP_WITHDRAWPROOFVERIFY;
|
||||
|
||||
if (stack.size() == 1) { // increasing value of locked coins
|
||||
if (!checker.GetValueIn().IsExplicit())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
CAmount minValue = checker.GetValueIn().GetAmount();
|
||||
CTxOut newOutput = checker.GetOutputOffsetFromCurrent(0);
|
||||
if (newOutput.IsNull()) {
|
||||
newOutput = checker.GetOutputOffsetFromCurrent(-1);
|
||||
if (!checker.GetValueInPrevIn().IsExplicit())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
minValue += checker.GetValueInPrevIn().GetAmount();
|
||||
}
|
||||
if (!newOutput.nValue.IsExplicit())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
if (newOutput.scriptPubKey != relockScript || newOutput.nValue.GetAmount() < minValue)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT);
|
||||
} else { // stack.size() >= 7...ie regular withdraw
|
||||
int stackReadPos = -2;
|
||||
|
||||
const valtype &vlockTxOutIndex = stacktop(stackReadPos--);
|
||||
|
||||
valtype vlockTx;
|
||||
if (!WithdrawProofReadStackItem(stack, fRequireMinimal, &stackReadPos, vlockTx))
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
valtype vmerkleBlock;
|
||||
if (!WithdrawProofReadStackItem(stack, fRequireMinimal, &stackReadPos, vmerkleBlock))
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
|
||||
if (stack.size() < size_t(-stackReadPos))
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
valtype vcontract = std::vector<unsigned char>(stacktop(stackReadPos--));
|
||||
|
||||
uint256 genesishash(vgenesisHash);
|
||||
|
||||
try {
|
||||
Sidechain::Bitcoin::CMerkleBlock merkleBlock;
|
||||
CDataStream merkleBlockStream(vmerkleBlock, SER_NETWORK, PROTOCOL_VERSION);
|
||||
merkleBlockStream >> merkleBlock;
|
||||
if (!merkleBlockStream.empty() || !CheckBitcoinProof(merkleBlock.header.GetHash(), merkleBlock.header.nBits))
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK);
|
||||
|
||||
vector<uint256> txHashes;
|
||||
vector<unsigned int> txIndices;
|
||||
if (merkleBlock.txn.ExtractMatches(txHashes, txIndices) != merkleBlock.header.hashMerkleRoot || txHashes.size() != 1)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK);
|
||||
|
||||
// We disallow returns from the genesis block, allowing sidechains to
|
||||
// make genesis outputs spendable with a 21m initially-locked-to-btc
|
||||
// distributing transaction.
|
||||
if (merkleBlock.header.GetHash() == genesishash)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK);
|
||||
|
||||
Sidechain::Bitcoin::CTransactionRef locktx;
|
||||
CDataStream locktxStream(vlockTx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
locktxStream >> locktx;
|
||||
if (!locktxStream.empty())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX);
|
||||
|
||||
int nlocktxOut = CScriptNum(vlockTxOutIndex, fRequireMinimal).getint();
|
||||
if (nlocktxOut < 0 || (unsigned int)nlocktxOut >= locktx->vout.size())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX);
|
||||
|
||||
if (locktx->GetHash() != txHashes[0])
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX);
|
||||
|
||||
if (vcontract.size() != 40)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT);
|
||||
|
||||
opcodetype opcodeTmp;
|
||||
CScript scriptDestination = checker.GetFedpegScript();
|
||||
{
|
||||
CScript::iterator sdpc = scriptDestination.begin();
|
||||
vector<unsigned char> vch;
|
||||
while (scriptDestination.GetOp(sdpc, opcodeTmp, vch))
|
||||
{
|
||||
assert((vch.size() == 33 && opcodeTmp < OP_PUSHDATA4) ||
|
||||
(opcodeTmp <= OP_16 && opcodeTmp >= OP_1) || opcodeTmp == OP_CHECKMULTISIG);
|
||||
if (vch.size() == 33)
|
||||
{
|
||||
unsigned char tweak[32];
|
||||
size_t pub_len = 33;
|
||||
int ret;
|
||||
unsigned char *pub_start = &(*(sdpc - pub_len));
|
||||
CHMAC_SHA256(pub_start, pub_len).Write(&vcontract[0], 40).Finalize(tweak);
|
||||
secp256k1_pubkey pubkey;
|
||||
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey, pub_start, pub_len);
|
||||
assert(ret == 1);
|
||||
// If someone creates a tweak that makes this fail, they broke SHA256
|
||||
ret = secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, &pubkey, tweak);
|
||||
assert(ret == 1);
|
||||
ret = secp256k1_ec_pubkey_serialize(secp256k1_ctx, pub_start, &pub_len, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
assert(ret == 1);
|
||||
assert(pub_len == 33);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CScriptID expectedP2SH(scriptDestination);
|
||||
if (locktx->vout[nlocktxOut].scriptPubKey != GetScriptForDestination(expectedP2SH))
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPTDEST);
|
||||
|
||||
vcontract.erase(vcontract.begin() + 4, vcontract.begin() + 20); // Remove the nonce from the contract before further processing
|
||||
assert(vcontract.size() == 24);
|
||||
|
||||
// We check values by doing the following:
|
||||
// * Tx must relock at least <unlocked coins> - <locked-on-bitcoin coins>
|
||||
// * Tx must send at least the withdraw value to its P2SH withdraw, but may send more
|
||||
CAmount withdrawVal = locktx->vout[nlocktxOut].nValue;
|
||||
if (!checker.GetValueIn().IsExplicit()) // Heh, you just destroyed coins
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
|
||||
CAmount lockValueRequired = checker.GetValueIn().GetAmount() - withdrawVal;
|
||||
if (lockValueRequired > 0) {
|
||||
const CTxOut newLockOutput = checker.GetOutputOffsetFromCurrent(1);
|
||||
if (!newLockOutput.nValue.IsExplicit())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
if (newLockOutput.IsNull() || newLockOutput.scriptPubKey != relockScript || newLockOutput.nValue.GetAmount() < lockValueRequired)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_RELOCK_SCRIPTVAL);
|
||||
}
|
||||
|
||||
const CTxOut withdrawOutput = checker.GetOutputOffsetFromCurrent(0);
|
||||
if (!withdrawOutput.nValue.IsExplicit())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS);
|
||||
if (withdrawOutput.nValue.GetAmount() < withdrawVal)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_VAL);
|
||||
|
||||
CScript expectedWithdrawScriptPubKey;
|
||||
if (vcontract[0] == 'P' && vcontract[1] == '2' && vcontract[2] == 'S' && vcontract[3] == 'H')
|
||||
expectedWithdrawScriptPubKey = CScript() << OP_HASH160 << std::vector<unsigned char>(vcontract.begin() + 4, vcontract.begin() + 24) << OP_EQUAL;
|
||||
else if (vcontract[0] == 'P' && vcontract[1] == '2' && vcontract[2] == 'P' && vcontract[3] == 'H')
|
||||
expectedWithdrawScriptPubKey = CScript() << OP_DUP << OP_HASH160 << std::vector<unsigned char>(vcontract.begin() + 4, vcontract.begin() + 24) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
else
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT);
|
||||
|
||||
if (withdrawOutput.scriptPubKey != expectedWithdrawScriptPubKey)
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPT);
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_NO_CALLRPC
|
||||
if (GetBoolArg("-validatepegin", DEFAULT_VALIDATE_PEGIN) && !checker.IsConfirmedBitcoinBlock(merkleBlock.header.GetHash(), flags & SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED, GetArg("-peginconfirmationdepth", DEFAULT_PEGIN_CONFIRMATION_DEPTH)))
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED);
|
||||
#endif
|
||||
} catch (std::exception& e) {
|
||||
// Probably invalid encoding of something which was deserialized
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT);
|
||||
}
|
||||
}
|
||||
} // else...OP_NOP3
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
||||
}
|
||||
|
||||
|
|
@ -1834,22 +1635,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
|
|||
return ss.GetHash();
|
||||
}
|
||||
|
||||
CTxOut BaseSignatureChecker::GetOutputOffsetFromCurrent(const int offset) const
|
||||
{
|
||||
return CTxOut();
|
||||
}
|
||||
|
||||
COutPoint BaseSignatureChecker::GetPrevOut() const
|
||||
{
|
||||
return COutPoint();
|
||||
}
|
||||
|
||||
bool TransactionNoWithdrawsSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
return pubkey.Verify(sighash, vchSig);
|
||||
}
|
||||
|
||||
bool TransactionNoWithdrawsSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
|
||||
bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
|
||||
{
|
||||
CPubKey pubkey(vchPubKey);
|
||||
if (!pubkey.IsValid())
|
||||
|
|
@ -1870,7 +1661,7 @@ bool TransactionNoWithdrawsSignatureChecker::CheckSig(const vector<unsigned char
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TransactionNoWithdrawsSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
// There are two kinds of nLockTime: lock-by-blockheight
|
||||
// and lock-by-blocktime, distinguished by whether
|
||||
|
|
@ -1906,7 +1697,7 @@ bool TransactionNoWithdrawsSignatureChecker::CheckLockTime(const CScriptNum& nLo
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TransactionNoWithdrawsSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
|
||||
bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
|
||||
{
|
||||
// Relative lock times are supported by comparing the passed
|
||||
// in operand to the sequence number of the input.
|
||||
|
|
@ -1952,38 +1743,6 @@ bool TransactionNoWithdrawsSignatureChecker::CheckSequence(const CScriptNum& nSe
|
|||
return true;
|
||||
}
|
||||
|
||||
CTxOut TransactionSignatureChecker::GetOutputOffsetFromCurrent(const int offset) const
|
||||
{
|
||||
assert(int(nIn) >= 0 && int(txTo->vout.size()) > 0);
|
||||
if (int(nIn) + offset < 0 || int(txTo->vout.size()) <= int(nIn) + offset)
|
||||
return CTxOut();
|
||||
return txTo->vout[int(nIn) + offset];
|
||||
}
|
||||
|
||||
COutPoint TransactionSignatureChecker::GetPrevOut() const
|
||||
{
|
||||
return txTo->vin[nIn].prevout;
|
||||
}
|
||||
|
||||
CConfidentialValue TransactionSignatureChecker::GetValueIn() const
|
||||
{
|
||||
return amount;
|
||||
}
|
||||
|
||||
CConfidentialValue TransactionSignatureChecker::GetValueInPrevIn() const
|
||||
{
|
||||
return amountPreviousInput;
|
||||
}
|
||||
|
||||
bool TransactionSignatureChecker::IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements, uint32_t nConfirmationsRequired) const
|
||||
{
|
||||
#ifndef BITCOIN_SCRIPT_NO_CALLRPC
|
||||
return ::IsConfirmedBitcoinBlock(hash, nConfirmationsRequired + (fConservativeConfirmationRequirements ? 2 : 0));
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
||||
{
|
||||
vector<vector<unsigned char> > stack;
|
||||
|
|
@ -2051,18 +1810,6 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
|
|||
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
|
||||
}
|
||||
|
||||
// If the scriptPubKey is not in exactly the withdrawlock format we expect,
|
||||
// we will not execute WITHDRAW-related opcodes (treating them as NOPs)
|
||||
// Additionally, if the scriptPubKey is a withdraw lock, the scriptSig must
|
||||
// be push only.
|
||||
if ((flags & SCRIPT_VERIFY_WITHDRAW) != 0) {
|
||||
if (scriptPubKey.IsWithdrawLock()) {
|
||||
if (!scriptSig.IsPushOnly())
|
||||
return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT);
|
||||
} else
|
||||
flags &= ~SCRIPT_VERIFY_WITHDRAW;
|
||||
}
|
||||
|
||||
vector<vector<unsigned char> > stack, stackCopy;
|
||||
if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
|
||||
// serror is set
|
||||
|
|
@ -2150,7 +1897,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
|
|||
// would be possible, which is not a softfork (and P2SH should be one).
|
||||
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
|
||||
assert((flags & SCRIPT_VERIFY_WITNESS) != 0);
|
||||
if (stack.size() != 1 && (flags & SCRIPT_VERIFY_WITHDRAW) == 0) {
|
||||
if (stack.size() != 1) {
|
||||
return set_error(serror, SCRIPT_ERR_CLEANSTACK);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,13 +108,6 @@ enum
|
|||
//
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
|
||||
|
||||
// Execute sidechain-related opcodes instead of treating them as NOPs
|
||||
//
|
||||
SCRIPT_VERIFY_WITHDRAW = (1U << 16),
|
||||
|
||||
// Dirty hack to require a higher bar of bitcoin block confirmation in mempool
|
||||
//
|
||||
SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED = (1U << 17)
|
||||
};
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
||||
|
|
@ -142,44 +135,20 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual CScript GetFedpegScript() const
|
||||
{
|
||||
CScript fedpegScript(CScript() << OP_FALSE);
|
||||
return fedpegScript;
|
||||
}
|
||||
|
||||
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual CTxOut GetOutputOffsetFromCurrent(const int offset) const;
|
||||
virtual COutPoint GetPrevOut() const;
|
||||
|
||||
virtual CConfidentialValue GetValueIn() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual bool CheckSequence(const CScriptNum& nSequence) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual CConfidentialValue GetValueInPrevIn() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements, uint32_t nConfirmationsRequired) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ~BaseSignatureChecker() {}
|
||||
};
|
||||
|
||||
class TransactionNoWithdrawsSignatureChecker : public BaseSignatureChecker
|
||||
class TransactionSignatureChecker : public BaseSignatureChecker
|
||||
{
|
||||
protected:
|
||||
const CTransaction* txTo;
|
||||
|
|
@ -190,40 +159,20 @@ protected:
|
|||
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
|
||||
public:
|
||||
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
|
||||
TransactionNoWithdrawsSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||
bool CheckSequence(const CScriptNum& nSequence) const;
|
||||
};
|
||||
|
||||
class MutableTransactionNoWithdrawsSignatureChecker : public TransactionNoWithdrawsSignatureChecker
|
||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CTransaction txTo;
|
||||
|
||||
public:
|
||||
MutableTransactionNoWithdrawsSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amount) : TransactionNoWithdrawsSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
|
||||
};
|
||||
|
||||
class TransactionSignatureChecker : public TransactionNoWithdrawsSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CConfidentialValue amountPreviousInput;
|
||||
const CScript fedpegScript;
|
||||
|
||||
public:
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const CConfidentialValue& amountPreviousInputIn, const CScript& fedpegScriptIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn), amountPreviousInput(amountPreviousInputIn), fedpegScript(fedpegScriptIn) {}
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const CConfidentialValue& amountPreviousInputIn, const PrecomputedTransactionData& txdataIn, const CScript& fedpegScriptIn) : TransactionNoWithdrawsSignatureChecker(txToIn, nInIn, amountIn, txdataIn), amountPreviousInput(amountPreviousInputIn), fedpegScript(fedpegScriptIn) {}
|
||||
CTxOut GetOutputOffsetFromCurrent(const int offset) const;
|
||||
COutPoint GetPrevOut() const;
|
||||
CConfidentialValue GetValueIn() const;
|
||||
CConfidentialValue GetValueInPrevIn() const;
|
||||
bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements, uint32_t nConfirmationsRequired) const;
|
||||
virtual CScript GetFedpegScript() const
|
||||
{
|
||||
return fedpegScript;
|
||||
}
|
||||
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
|
||||
};
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
|
|||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_WITHDRAW_LOCK:
|
||||
case TX_FEE:
|
||||
break;
|
||||
case TX_PUBKEY:
|
||||
|
|
|
|||
|
|
@ -215,151 +215,6 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
|||
return subscript.GetSigOpCount(true);
|
||||
}
|
||||
|
||||
bool CScript::IsWithdrawProof() const
|
||||
{
|
||||
// Format is <contract> <merkleBlock>xN <N> <locking tx>xM <M> <output index>
|
||||
// for at least 6 total pushes
|
||||
// Here we simply check that the script is push-only and has at least 6 pushes.
|
||||
// The output must be P2SH to the appropriate script
|
||||
const_iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
uint32_t push_count = 0;
|
||||
while (pc < end())
|
||||
{
|
||||
if (!GetOp(pc, opcode))
|
||||
return false;
|
||||
if (opcode > OP_16 || opcode == OP_RESERVED)
|
||||
return false;
|
||||
push_count++;
|
||||
}
|
||||
return push_count >= 6;
|
||||
}
|
||||
|
||||
bool CScript::IsWithdrawLock() const
|
||||
{
|
||||
// Locks look like [<chaindest> OP_DROP] <genesishash> OP_WITHDRAWPROOFVERIFY
|
||||
// This function must return true for an OP_WITHDRAWPROOFVERIFY opcode to execute.
|
||||
// We require all pushes be in their minimal form, to make inspection of
|
||||
// withdraw locks a purely byte-matching affair.
|
||||
const_iterator pc = begin();
|
||||
vector<unsigned char> data;
|
||||
opcodetype opcode;
|
||||
|
||||
if (!GetOp(pc, opcode, data))
|
||||
return false;
|
||||
if (opcode == 24 && data.size() == 24) { // 4 byte type + 20 byte destination is suggested
|
||||
if (!GetOp(pc, opcode, data) || opcode != OP_DROP || data.size() != 0)
|
||||
return false;
|
||||
|
||||
if (!GetOp(pc, opcode, data))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opcode != 32 || data.size() != 32)
|
||||
return false;
|
||||
|
||||
if (!GetOp(pc, opcode, data) || opcode != OP_WITHDRAWPROOFVERIFY || data.size() != 0)
|
||||
return false;
|
||||
|
||||
if (GetOp(pc, opcode))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 CScript::GetWithdrawLockGenesisHash() const
|
||||
{
|
||||
assert(IsWithdrawLock());
|
||||
|
||||
const_iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
vector<unsigned char> vchgenesishash;
|
||||
|
||||
bool ret;
|
||||
ret = GetOp(pc, opcode, vchgenesishash);
|
||||
assert(ret);
|
||||
if (vchgenesishash.size() != 32) {
|
||||
ret = GetOp(pc, opcode);
|
||||
assert(ret && opcode == OP_DROP);
|
||||
ret = GetOp(pc, opcode, vchgenesishash);
|
||||
assert(ret);
|
||||
}
|
||||
assert(vchgenesishash.size() == 32);
|
||||
return uint256(vchgenesishash);
|
||||
}
|
||||
|
||||
static bool PopWithdrawPush(vector<vector<unsigned char> >& pushes, vector<unsigned char> *read=NULL) {
|
||||
if (pushes.empty())
|
||||
return false;
|
||||
int pushCount = CScriptNum(pushes.back(), false).getint();
|
||||
pushes.pop_back();
|
||||
if (pushCount < 0 || pushCount > 2000 || pushes.size() < size_t(pushCount))
|
||||
return false;
|
||||
for (int i = pushCount; i > 0; i--) {
|
||||
if (i != 1 && pushes[pushes.size() - i].size() != 520)
|
||||
return false;
|
||||
if (read != NULL) {
|
||||
const vector<unsigned char> &push = pushes[pushes.size() - i];
|
||||
read->insert(read->end(), push.begin(), push.end());
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < pushCount; i++)
|
||||
pushes.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
COutPoint CScript::GetWithdrawSpent() const
|
||||
{
|
||||
assert(IsWithdrawProof());
|
||||
|
||||
try {
|
||||
const_iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
|
||||
// We have to read the script from back-to-front, so we stack-ize it
|
||||
vector<vector<unsigned char> > pushes;
|
||||
pushes.reserve(6);
|
||||
while (pc < end()) {
|
||||
pushes.push_back(vector<unsigned char>());
|
||||
assert(GetOp(pc, opcode, pushes.back()));
|
||||
if (opcode <= OP_16 && opcode >= OP_1)
|
||||
pushes.back().push_back(opcode - OP_1 + 1);
|
||||
else if (opcode == OP_1NEGATE)
|
||||
pushes.back().push_back(0x81);
|
||||
}
|
||||
|
||||
int ntxOut = CScriptNum(pushes.back(), false).getint();
|
||||
pushes.pop_back();
|
||||
|
||||
vector<unsigned char> vTx;
|
||||
if (!PopWithdrawPush(pushes, &vTx))
|
||||
return COutPoint();
|
||||
Sidechain::Bitcoin::CTransactionRef tx;
|
||||
CDataStream(vTx, SER_NETWORK, PROTOCOL_VERSION) >> tx;
|
||||
|
||||
if (ntxOut < 0 || (unsigned int)ntxOut >= tx->vout.size())
|
||||
return COutPoint();
|
||||
|
||||
return COutPoint(tx->GetHash(), ntxOut);
|
||||
} catch (std::exception& e) {
|
||||
return COutPoint();
|
||||
}
|
||||
}
|
||||
|
||||
void CScript::PushWithdraw(const vector<unsigned char> push) {
|
||||
int64_t pushCount = 0;
|
||||
for (vector<unsigned char>::const_iterator it = push.begin(); it < push.end(); pushCount++) {
|
||||
if (push.end() - it < 520) {
|
||||
*this << vector<unsigned char>(it, push.end());
|
||||
it = push.end();
|
||||
} else {
|
||||
*this << vector<unsigned char>(it, it + 520);
|
||||
it += 520;
|
||||
}
|
||||
}
|
||||
*this << pushCount;
|
||||
}
|
||||
|
||||
bool CScript::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
|
|
|
|||
|
|
@ -636,24 +636,6 @@ public:
|
|||
bool IsPayToScriptHash() const;
|
||||
bool IsPayToWitnessScriptHash() const;
|
||||
bool IsWitnessProgram(int& version, std::vector<unsigned char>& program) const;
|
||||
/**
|
||||
* Returns true if this is a withdraw-lock scriptPubKey.
|
||||
* Note that a withdraw-lock could be a plan [re-]lock output *or* a
|
||||
* x-chain transfer lock.
|
||||
*/
|
||||
bool IsWithdrawLock() const;
|
||||
|
||||
/** Returns true if this is a proof-of-withdraw, spending an IsWithdrawLock */
|
||||
bool IsWithdrawProof() const;
|
||||
|
||||
//! Push a vector with a length postfix (as used by withdraw proofs)
|
||||
void PushWithdraw(const std::vector<unsigned char> push);
|
||||
|
||||
/** Get the withdraw output spent, asserting IsWithdrawProof first */
|
||||
COutPoint GetWithdrawSpent() const;
|
||||
|
||||
/** Get the genesis hash locked to, asserting IsWithdrawLock first */
|
||||
uint256 GetWithdrawLockGenesisHash() const;
|
||||
|
||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||
bool IsPushOnly(const_iterator pc) const;
|
||||
|
|
|
|||
|
|
@ -87,26 +87,6 @@ const char* ScriptErrorString(const ScriptError serror)
|
|||
return "Witness provided for non-witness script";
|
||||
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
||||
return "Using non-compressed keys in segwit";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT:
|
||||
return "Withdraw proof validation failed - invalid proof format";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK:
|
||||
return "Withdraw proof validation failed - SPV proof/block coinbase invalid";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX:
|
||||
return "Withdraw proof validation failed - locking transaction misformatted";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT:
|
||||
return "Withdraw proof validation failed - output does not match expected";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED:
|
||||
return "Withdraw proof validation failed - lock block was not sufficiently confirmed on sending chain";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS:
|
||||
return "Withdraw proof validation failed - amounts in outputs were blinded";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPTDEST:
|
||||
return "Withdraw proof validation failed - Bitcoin output script destination does not match federation script";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_RELOCK_SCRIPTVAL:
|
||||
return "Withdraw proof validation failed - Relock scriptpubkey or value is invalid";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_VAL:
|
||||
return "Withdraw proof validation failed - Withdraw output value invalid";
|
||||
case SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPT:
|
||||
return "Withdraw proof validation failed - Sidechain pegin destination does not match expected";
|
||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||
case SCRIPT_ERR_ERROR_COUNT:
|
||||
default: break;
|
||||
|
|
|
|||
|
|
@ -64,19 +64,6 @@ typedef enum ScriptError_t
|
|||
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
||||
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
||||
|
||||
/* sidechains */
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPTDEST,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_RELOCK_SCRIPTVAL,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_VAL,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT_SCRIPT,
|
||||
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED,
|
||||
SCRIPT_ERR_WITHDRAW_VERIFY_BLINDED_AMOUNTS,
|
||||
|
||||
SCRIPT_ERR_ERROR_COUNT,
|
||||
|
||||
SCRIPT_ERR_RANGEPROOF,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ private:
|
|||
bool store;
|
||||
|
||||
public:
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amount, const CConfidentialValue& amountPreviousInput, const CScript& scriptFedRedeem, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, amountPreviousInput, scriptFedRedeem), store(storeIn) {}
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
|||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_WITHDRAW_LOCK:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
|
|
@ -319,7 +318,6 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
|
|||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_WITHDRAW_LOCK:
|
||||
case TX_TRUE:
|
||||
// Don't know anything about this, assume bigger one is correct:
|
||||
if (sigs1.script.size() >= sigs2.script.size())
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
|
|||
unsigned int nIn;
|
||||
int nHashType;
|
||||
CConfidentialValue amount;
|
||||
const TransactionNoWithdrawsSignatureChecker checker;
|
||||
const TransactionSignatureChecker checker;
|
||||
|
||||
public:
|
||||
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, int nHashTypeIn=SIGHASH_ALL);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ const char* GetTxnOutputType(txnouttype t)
|
|||
case TX_NULL_DATA: return "nulldata";
|
||||
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
|
||||
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
|
||||
case TX_WITHDRAW_LOCK: return "withdraw";
|
||||
case TX_TRUE: return "true";
|
||||
case TX_FEE: return "fee";
|
||||
}
|
||||
|
|
@ -107,12 +106,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
return true;
|
||||
}
|
||||
|
||||
if (scriptPubKey.IsWithdrawLock())
|
||||
{
|
||||
typeRet = TX_WITHDRAW_LOCK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
|
|
@ -235,7 +228,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
|
|||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
||||
return false;
|
||||
if (typeRet == TX_NULL_DATA || typeRet == TX_WITHDRAW_LOCK || typeRet == TX_FEE){
|
||||
if (typeRet == TX_NULL_DATA || typeRet == TX_FEE){
|
||||
// This is data, not addresses
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ extern unsigned nMaxDatacarrierBytes;
|
|||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* details.
|
||||
*/
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | SCRIPT_VERIFY_WITHDRAW;
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
|
||||
|
||||
enum txnouttype
|
||||
{
|
||||
|
|
@ -53,7 +53,6 @@ enum txnouttype
|
|||
TX_NULL_DATA,
|
||||
TX_WITNESS_V0_SCRIPTHASH,
|
||||
TX_WITNESS_V0_KEYHASH,
|
||||
TX_WITHDRAW_LOCK,
|
||||
TX_TRUE,
|
||||
TX_FEE,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chainparams.h"
|
||||
#include "coins.h"
|
||||
#include "consensus/consensus.h"
|
||||
#include "consensus/merkle.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "validation.h"
|
||||
#include "miner.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/standard.h"
|
||||
#include "txmempool.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "random.h"
|
||||
|
||||
#include "txdb.h"
|
||||
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(lockedutxo_tests, TestingSetup)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Getlocked_validity)
|
||||
{
|
||||
std::multimap<uint256, std::pair<COutPoint, CAmount> > mLocksCreated;
|
||||
|
||||
uint256 gen0 = uint256S("0");
|
||||
|
||||
CMutableTransaction mtx0;
|
||||
mtx0.vout.push_back(CTxOut(CConfidentialAsset(Params().GetConsensus().pegged_asset), CConfidentialValue(1000), CScript() << OP_TRUE));
|
||||
CMutableTransaction mtx1;
|
||||
mtx1.vout.push_back(CTxOut(CConfidentialAsset(Params().GetConsensus().pegged_asset), CConfidentialValue(100), CScript() << OP_TRUE));
|
||||
CMutableTransaction mtx2;
|
||||
mtx2.vout.push_back(CTxOut(CConfidentialAsset(Params().GetConsensus().pegged_asset), CConfidentialValue(10), CScript() << OP_TRUE));
|
||||
CMutableTransaction mtx3;
|
||||
mtx3.vout.push_back(CTxOut(CConfidentialAsset(Params().GetConsensus().pegged_asset), CConfidentialValue(1), CScript() << OP_TRUE));
|
||||
|
||||
//Push vout of size 1 for each CCoin
|
||||
pcoinsTip->ModifyCoins(uint256S("0"))->FromTx(CTransaction(mtx0), 0);
|
||||
pcoinsTip->ModifyCoins(uint256S("1"))->FromTx(CTransaction(mtx1), 0);
|
||||
pcoinsTip->ModifyCoins(uint256S("2"))->FromTx(CTransaction(mtx2), 0);
|
||||
pcoinsTip->ModifyCoins(uint256S("3"))->FromTx(CTransaction(mtx3), 0);
|
||||
|
||||
//These coins need to exist, otherwise they will be deleted during GetLockedOutputs call
|
||||
CAmount value = 1000;
|
||||
mLocksCreated.insert(std::make_pair(gen0, std::make_pair(COutPoint(uint256S("0"), 0), value)));
|
||||
value = 100;
|
||||
mLocksCreated.insert(std::make_pair(gen0, std::make_pair(COutPoint(uint256S("1"), 0), value)));
|
||||
value = 10;
|
||||
mLocksCreated.insert(std::make_pair(gen0, std::make_pair(COutPoint(uint256S("2"), 0), value)));
|
||||
value = 1;
|
||||
mLocksCreated.insert(std::make_pair(gen0, std::make_pair(COutPoint(uint256S("3"), 0), value)));
|
||||
|
||||
//Write list of 4
|
||||
pblocktree->WriteLocksCreated(mLocksCreated);
|
||||
|
||||
//Read the list back, ensure it was written correctly
|
||||
std::vector<std::pair<COutPoint, CAmount> > locksCreated;
|
||||
assert(pblocktree->ReadLocksCreated(gen0, locksCreated));
|
||||
assert(locksCreated.size() == 4);
|
||||
std::multimap<uint256, std::pair<COutPoint, CAmount> >::iterator it = mLocksCreated.equal_range(gen0).first;
|
||||
assert(locksCreated[0] == it->second);
|
||||
std::advance(it, 1);
|
||||
assert(locksCreated[1] == it->second);
|
||||
std::advance(it, 1);
|
||||
assert(locksCreated[2] == it->second);
|
||||
std::advance(it, 1);
|
||||
assert(locksCreated[3] == it->second);
|
||||
|
||||
//Call GetLockedOutputs to get the single output large enough
|
||||
CAmount desiredAmount = 101;
|
||||
std::vector<std::pair<COutPoint, CAmount> > res;
|
||||
assert(GetLockedOutputs(gen0, desiredAmount, res));
|
||||
assert(res.size() == 1 && res[0].second == 1000);
|
||||
|
||||
//Read it back again
|
||||
std::vector<std::pair<COutPoint, CAmount> > locksCreated2;
|
||||
assert(pblocktree->ReadLocksCreated(gen0, locksCreated2));
|
||||
assert(locksCreated2.size() == 4);
|
||||
|
||||
//Write a blank list and read it back
|
||||
std::vector<std::pair<COutPoint, CAmount> > locksCreated3;
|
||||
pblocktree->ReWriteLocksCreated(gen0, locksCreated3);
|
||||
assert(pblocktree->ReadLocksCreated(gen0, locksCreated3));
|
||||
assert(locksCreated3.size() == 0);
|
||||
|
||||
//Delete the largest element, and read back
|
||||
locksCreated.erase(locksCreated.begin());
|
||||
pblocktree->ReWriteLocksCreated(gen0, locksCreated);
|
||||
assert(pblocktree->ReadLocksCreated(gen0, locksCreated));
|
||||
assert(locksCreated.size() == 3);
|
||||
|
||||
//Find at least 2 utxos to fulfill amount
|
||||
std::vector<std::pair<COutPoint, CAmount> > res2;
|
||||
assert(GetLockedOutputs(gen0, desiredAmount, res2));
|
||||
assert(res2.size() > 1);
|
||||
|
||||
//Delete the second-largest element, and read back
|
||||
locksCreated.erase(locksCreated.begin());
|
||||
pblocktree->ReWriteLocksCreated(gen0, locksCreated);
|
||||
assert(pblocktree->ReadLocksCreated(gen0, locksCreated));
|
||||
assert(locksCreated.size() == 2);
|
||||
|
||||
//Will not find enough, but will return the last 2
|
||||
std::vector<std::pair<COutPoint, CAmount> > res3;
|
||||
assert(!GetLockedOutputs(gen0, desiredAmount, res3));
|
||||
assert(res3.size() == 2);
|
||||
|
||||
|
||||
// Make sure this terminates
|
||||
for (unsigned int i = 0; i < 10000; i++) {
|
||||
// Make random set of 100 utxos
|
||||
std::vector<std::pair<COutPoint, CAmount> > locksCreated4;
|
||||
for (unsigned int j = 0; j < GetRand(100); j++) {
|
||||
locksCreated4.push_back(std::make_pair(COutPoint(GetRandHash(), GetRand(10)), GetRand(100000)));
|
||||
}
|
||||
pblocktree->ReWriteLocksCreated(gen0, locksCreated4);
|
||||
CAmount desiredAmount = GetRand(1000000);
|
||||
std::vector<std::pair<COutPoint, CAmount> > res;
|
||||
GetLockedOutputs(gen0, desiredAmount, res);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
@ -422,8 +422,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
|
|||
/* after tx6 is mined, tx7 should move up in the sort */
|
||||
std::vector<CTransactionRef> vtx;
|
||||
vtx.push_back(MakeTransactionRef(tx6));
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
pool.removeForBlock(vtx, 1, setWithdrawsSpent);
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
pool.removeForBlock(vtx, 1, setPeginsSpent);
|
||||
|
||||
sortedOrder.erase(sortedOrder.begin()+1);
|
||||
// Ties are broken by hash
|
||||
|
|
@ -566,8 +566,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
|||
SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
|
||||
// ... we should keep the same min fee until we get a block
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
pool.removeForBlock(vtx, 1, setWithdrawsSpent);
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
pool.removeForBlock(vtx, 1, setPeginsSpent);
|
||||
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
|
||||
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), (maxFeeRateRemoved.GetFeePerK() + 1000)/2);
|
||||
// ... then feerate should drop 1/2 each halflife
|
||||
|
|
@ -595,7 +595,7 @@ BOOST_AUTO_TEST_CASE(WithdrawsSpentTest)
|
|||
{
|
||||
CTxMemPool pool(CFeeRate(0));
|
||||
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
TestMemPoolEntryHelper entry;
|
||||
|
||||
std::pair<uint256, COutPoint> withdraw1, withdraw2, withdraw3;
|
||||
|
|
@ -614,63 +614,63 @@ BOOST_AUTO_TEST_CASE(WithdrawsSpentTest)
|
|||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = 0;
|
||||
const uint256 tx1Hash(tx.GetHash());
|
||||
pool.addUnchecked(tx1Hash, entry.WithdrawsSpent(setWithdrawsSpent).FromTx(tx));
|
||||
pool.addUnchecked(tx1Hash, entry.WithdrawsSpent(setPeginsSpent).FromTx(tx));
|
||||
BOOST_CHECK(pool.mapWithdrawsSpentToTxid.empty());
|
||||
|
||||
setWithdrawsSpent = {withdraw1};
|
||||
setPeginsSpent = {withdraw1};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(2);
|
||||
tx.vout[1].nValue = 0;
|
||||
const uint256 tx2Hash(tx.GetHash());
|
||||
pool.addUnchecked(tx2Hash, entry.WithdrawsSpent(setWithdrawsSpent).FromTx(tx));
|
||||
pool.addUnchecked(tx2Hash, entry.WithdrawsSpent(setPeginsSpent).FromTx(tx));
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw1].ToString(), tx2Hash.ToString());
|
||||
|
||||
setWithdrawsSpent = {withdraw2};
|
||||
setPeginsSpent = {withdraw2};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(3);
|
||||
tx.vout[2].nValue = 0;
|
||||
const uint256 tx3Hash(tx.GetHash());
|
||||
pool.addUnchecked(tx3Hash, entry.WithdrawsSpent(setWithdrawsSpent).FromTx(tx));
|
||||
pool.addUnchecked(tx3Hash, entry.WithdrawsSpent(setPeginsSpent).FromTx(tx));
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw2].ToString(), tx3Hash.ToString());
|
||||
|
||||
setWithdrawsSpent = {withdraw3};
|
||||
setPeginsSpent = {withdraw3};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(4);
|
||||
tx.vout[3].nValue = 0;
|
||||
CTransactionRef txref(MakeTransactionRef(tx));
|
||||
pool.removeForBlock({txref}, 1, setWithdrawsSpent);
|
||||
pool.removeForBlock({txref}, 1, setPeginsSpent);
|
||||
|
||||
BOOST_CHECK_EQUAL(pool.size(), 3);
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid.size(), 2);
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw1].ToString(), tx2Hash.ToString());
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw2].ToString(), tx3Hash.ToString());
|
||||
|
||||
setWithdrawsSpent = {withdraw1};
|
||||
setPeginsSpent = {withdraw1};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(5);
|
||||
tx.vout[4].nValue = 0;
|
||||
txref = MakeTransactionRef(tx);
|
||||
pool.removeForBlock({txref}, 2, setWithdrawsSpent);
|
||||
pool.removeForBlock({txref}, 2, setPeginsSpent);
|
||||
|
||||
BOOST_CHECK_EQUAL(pool.size(), 2);
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid.size(), 1);
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw2].ToString(), tx3Hash.ToString());
|
||||
|
||||
setWithdrawsSpent = {withdraw1, withdraw3};
|
||||
setPeginsSpent = {withdraw1, withdraw3};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(6);
|
||||
tx.vout[5].nValue = 0;
|
||||
const uint256 tx4Hash(tx.GetHash());
|
||||
pool.addUnchecked(tx4Hash, entry.WithdrawsSpent(setWithdrawsSpent).FromTx(tx));
|
||||
pool.addUnchecked(tx4Hash, entry.WithdrawsSpent(setPeginsSpent).FromTx(tx));
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw1].ToString(), tx4Hash.ToString());
|
||||
BOOST_CHECK_EQUAL(pool.mapWithdrawsSpentToTxid[withdraw3].ToString(), tx4Hash.ToString());
|
||||
|
||||
setWithdrawsSpent = {withdraw2, withdraw3};
|
||||
setPeginsSpent = {withdraw2, withdraw3};
|
||||
GetRandBytes(tx.vin[0].prevout.hash.begin(), tx.vin[0].prevout.hash.size());
|
||||
tx.vout.resize(7);
|
||||
tx.vout[6].nValue = 0;
|
||||
txref = MakeTransactionRef(tx);
|
||||
pool.removeForBlock({txref}, 3, setWithdrawsSpent);
|
||||
pool.removeForBlock({txref}, 3, setPeginsSpent);
|
||||
|
||||
BOOST_CHECK_EQUAL(pool.size(), 1);
|
||||
BOOST_CHECK(pool.mapWithdrawsSpentToTxid.empty());
|
||||
|
|
|
|||
|
|
@ -80,20 +80,20 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
keys.assign(1,key[0]);
|
||||
keys.push_back(key[1]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[0], 0, amount), &err));
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.assign(1,key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||
|
||||
keys.assign(1,key[1]);
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
|
@ -104,18 +104,18 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
||||
if (i == 0 || i == 1)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
}
|
||||
s.clear();
|
||||
s << OP_0 << OP_1;
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[1], 0, amount), &err));
|
||||
BOOST_CHECK(!VerifyScript(s, a_or_b, NULL, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
|
||||
|
||||
|
||||
|
|
@ -127,12 +127,12 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
|||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
||||
if (i < j && i < 3 && j < 3)
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, NULL, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, NULL, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
|
|||
txTo.vin[0].scriptSig = scriptSig;
|
||||
txTo.vout[0].nValue = 1;
|
||||
|
||||
return VerifyScript(scriptSig, scriptPubKey, NULL, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err);
|
||||
return VerifyScript(scriptSig, scriptPubKey, NULL, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(sign)
|
|||
{
|
||||
CScript sigSave = txTo[i].vin[0].scriptSig;
|
||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
||||
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, -1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
|
||||
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
|
||||
if (i == j)
|
||||
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||
else
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ return;
|
|||
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue);
|
||||
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, scriptWitness, txCredit);
|
||||
CMutableTransaction tx2 = tx;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, txCredit.vout[0].scriptPubKey, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, txCredit.vout[0].scriptPubKey, NULL, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message);
|
||||
BOOST_CHECK_MESSAGE(err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message);
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
|
@ -1077,18 +1077,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
|||
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12);
|
||||
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
txTo12.vout[0].nValue = 2;
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
|
@ -1110,54 +1110,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
|||
std::vector<CKey> keys;
|
||||
keys.push_back(key1); keys.push_back(key2);
|
||||
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key3);
|
||||
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key3);
|
||||
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
||||
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
||||
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
||||
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
||||
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear();
|
||||
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
||||
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||
|
||||
keys.clear(); // Must have signatures
|
||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, flags, MutableTransactionNoWithdrawsSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err));
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||
}
|
||||
|
||||
|
|
@ -1183,19 +1183,19 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|||
CScript& scriptSig = txTo.vin[0].scriptSig;
|
||||
|
||||
SignatureData empty;
|
||||
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), empty, empty);
|
||||
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty);
|
||||
BOOST_CHECK(combined.scriptSig.empty());
|
||||
|
||||
// Single signature case:
|
||||
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
CScript scriptSigCopy = scriptSig;
|
||||
// Signing again will give a different, valid signature:
|
||||
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
|
||||
|
||||
// P2SH, single-signature case:
|
||||
|
|
@ -1203,28 +1203,28 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|||
keystore.AddCScript(pkSingle);
|
||||
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
|
||||
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
scriptSigCopy = scriptSig;
|
||||
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
|
||||
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
|
||||
scriptSigCopy = CScript() << OP_0 << std::vector<unsigned char>(pkSingle.begin(), pkSingle.end());
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
|
||||
// Hardest case: Multisig 2-of-3
|
||||
scriptPubKey = GetScriptForMultisig(2, pubkeys);
|
||||
keystore.AddCScript(scriptPubKey);
|
||||
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty);
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig));
|
||||
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||
|
||||
// A couple of partially-signed versions:
|
||||
|
|
@ -1253,21 +1253,21 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
|||
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
|
||||
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
|
||||
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b));
|
||||
BOOST_CHECK(combined.scriptSig == partial1a);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a));
|
||||
BOOST_CHECK(combined.scriptSig == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a));
|
||||
BOOST_CHECK(combined.scriptSig == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b));
|
||||
BOOST_CHECK(combined.scriptSig == complete12);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b));
|
||||
BOOST_CHECK(combined.scriptSig == complete13);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a));
|
||||
BOOST_CHECK(combined.scriptSig == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b));
|
||||
BOOST_CHECK(combined.scriptSig == complete23);
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
|
||||
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a));
|
||||
BOOST_CHECK(combined.scriptSig == partial3c);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ ScriptError VerifyWithFlag(const CTransaction& output, const CMutableTransaction
|
|||
{
|
||||
ScriptError error;
|
||||
CTransaction inputi(input);
|
||||
bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, inputi.wit.vtxinwit.size() > 0 ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue, -1, CScript()), &error);
|
||||
bool ret = VerifyScript(inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, inputi.wit.vtxinwit.size() > 0 ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error);
|
||||
BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK));
|
||||
|
||||
return error;
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPo
|
|||
CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? TotalValueOut(txn) : 0;
|
||||
|
||||
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
|
||||
inChainValue, spendsCoinbase, sigOpCost, lp, setWithdrawsSpent);
|
||||
inChainValue, spendsCoinbase, sigOpCost, lp, setPeginsSpent);
|
||||
}
|
||||
|
||||
void Shutdown(void* parg)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ struct TestMemPoolEntryHelper
|
|||
bool spendsCoinbase;
|
||||
unsigned int sigOpCost;
|
||||
LockPoints lp;
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
|
||||
TestMemPoolEntryHelper() :
|
||||
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
|
||||
|
|
@ -89,6 +89,6 @@ struct TestMemPoolEntryHelper
|
|||
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
|
||||
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
|
||||
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
|
||||
TestMemPoolEntryHelper &WithdrawsSpent(std::set<std::pair<uint256, COutPoint> >& _setWithdrawsSpent) { setWithdrawsSpent = _setWithdrawsSpent; return *this; }
|
||||
TestMemPoolEntryHelper &WithdrawsSpent(std::set<std::pair<uint256, COutPoint> >& _setPeginsSpent) { setPeginsSpent = _setPeginsSpent; return *this; }
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ return;
|
|||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||
const CScriptWitness *witness = (tx.wit.vtxinwit.size() > i) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
witness, verify_flags, TransactionNoWithdrawsSignatureChecker(&tx, i, amount, txdata), &err),
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
|
||||
strTest);
|
||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
}
|
||||
|
|
@ -257,7 +257,7 @@ return;
|
|||
}
|
||||
const CScriptWitness *witness = (tx.wit.vtxinwit.size() > i) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
|
||||
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||
witness, verify_flags, TransactionNoWithdrawsSignatureChecker(&tx, i, amount, txdata), &err);
|
||||
witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
|
||||
}
|
||||
BOOST_CHECK_MESSAGE(!fValid, strTest);
|
||||
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||
|
|
@ -400,7 +400,7 @@ void CheckWithFlag(const CTransactionRef& output, const CMutableTransaction& inp
|
|||
{
|
||||
ScriptError error;
|
||||
CTransaction inputi(input);
|
||||
bool ret = VerifyScript(inputi.vin[0].scriptSig, output->vout[0].scriptPubKey, (inputi.wit.vtxinwit.size() > 0) ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionNoWithdrawsSignatureChecker(&inputi, 0, output->vout[0].nValue), &error);
|
||||
bool ret = VerifyScript(inputi.vin[0].scriptSig, output->vout[0].scriptPubKey, (inputi.wit.vtxinwit.size() > 0) ? &inputi.wit.vtxinwit[0].scriptWitness : NULL, flags, TransactionSignatureChecker(&inputi, 0, output->vout[0].nValue), &error);
|
||||
assert(ret == success);
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +496,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
|
|||
CScriptCheck* checks[mtx.vin.size()];
|
||||
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
|
||||
std::vector<CScriptCheck*> vChecks;
|
||||
checks[i] = new CScriptCheck(coins, tx, i, 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
|
||||
checks[i] = new CScriptCheck(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
|
||||
vChecks.push_back(checks[i]);
|
||||
control.Add(vChecks);
|
||||
}
|
||||
|
|
@ -643,7 +643,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
|||
CreateCreditAndSpend(keystore2, scriptMulti, output2, input2, false);
|
||||
CheckWithFlag(output2, input2, 0, false);
|
||||
BOOST_CHECK(*output1 == *output2);
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
||||
|
||||
// P2SH 2-of-2 multisig
|
||||
|
|
@ -654,7 +654,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
|||
CheckWithFlag(output2, input2, 0, true);
|
||||
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false);
|
||||
BOOST_CHECK(*output1 == *output2);
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
|
||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
||||
|
||||
|
|
@ -666,7 +666,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
|||
CheckWithFlag(output2, input2, 0, true);
|
||||
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
|
||||
BOOST_CHECK(*output1 == *output2);
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
|
||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
||||
|
||||
|
|
@ -678,7 +678,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
|||
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true);
|
||||
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
|
||||
BOOST_CHECK(*output1 == *output2);
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionNoWithdrawsSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
UpdateTransaction(input1, 0, CombineSignatures(output1->vout[0].scriptPubKey, MutableTransactionSignatureChecker(&input1, 0, output1->vout[0].nValue), DataFromTransaction(input1, 0), DataFromTransaction(input2, 0)));
|
||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true);
|
||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
||||
}
|
||||
|
|
|
|||
30
src/txdb.cpp
30
src/txdb.cpp
|
|
@ -171,36 +171,6 @@ bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos>
|
|||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteLocksCreated(const std::multimap<uint256, std::pair<COutPoint, CAmount> > &map) {
|
||||
if (map.size() == 0)
|
||||
return true;
|
||||
|
||||
uint256 prevGenesis;
|
||||
CDBBatch batch(*this);
|
||||
std::vector<std::pair<COutPoint, CAmount> > vLocks;
|
||||
for (std::multimap<uint256, std::pair<COutPoint, CAmount> >::const_iterator it=map.begin(); it!=map.end(); it++) {
|
||||
if (prevGenesis != it->first || it == map.begin()) {
|
||||
if (it != map.begin())
|
||||
batch.Write(std::make_pair(DB_LOCKS, prevGenesis), vLocks);
|
||||
prevGenesis = it->first;
|
||||
if (!Read(std::make_pair(DB_LOCKS, it->first), vLocks))
|
||||
vLocks.clear();
|
||||
}
|
||||
vLocks.push_back(it->second);
|
||||
}
|
||||
batch.Write(std::make_pair(DB_LOCKS, prevGenesis), vLocks);
|
||||
return WriteBatch(batch);
|
||||
}
|
||||
|
||||
|
||||
bool CBlockTreeDB::ReadLocksCreated(const uint256 &genesisHash, std::vector<std::pair<COutPoint, CAmount> > &vLocks) {
|
||||
return Read(std::make_pair(DB_LOCKS, genesisHash), vLocks);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::ReWriteLocksCreated(const uint256 &genesisHash, const std::vector<std::pair<COutPoint, CAmount> > &vLocks) {
|
||||
return Write(std::make_pair(DB_LOCKS, genesisHash), vLocks);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
|
||||
return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,9 +121,6 @@ public:
|
|||
bool ReadReindexing(bool &fReindex);
|
||||
bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
|
||||
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
|
||||
bool WriteLocksCreated(const std::multimap<uint256, std::pair<COutPoint, CAmount> > &list);
|
||||
bool ReadLocksCreated(const uint256 &genesisHash, std::vector<std::pair<COutPoint, CAmount> > &vLocks);
|
||||
bool ReWriteLocksCreated(const uint256 &genesisHash, const std::vector<std::pair<COutPoint, CAmount> > &vLocks);
|
||||
bool WriteFlag(const std::string &name, bool fValue);
|
||||
bool ReadFlag(const std::string &name, bool &fValue);
|
||||
bool LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@
|
|||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
CAmount _inChainInputValue,
|
||||
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp, std::set<std::pair<uint256, COutPoint> >& _setWithdrawsSpent):
|
||||
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp, std::set<std::pair<uint256, COutPoint> >& _setPeginsSpent):
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||
inChainInputValue(_inChainInputValue),
|
||||
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp), setWithdrawsSpent(_setWithdrawsSpent)
|
||||
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp), setPeginsSpent(_setPeginsSpent)
|
||||
{
|
||||
nTxWeight = GetTransactionWeight(*tx);
|
||||
nModSize = tx->CalculateModifiedSize(GetTxSize());
|
||||
|
|
@ -448,9 +448,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
|||
vTxHashes.emplace_back(tx.GetHashWithWitness(), newit);
|
||||
newit->vTxHashesIdx = vTxHashes.size() - 1;
|
||||
|
||||
typedef std::pair<uint256, COutPoint> WithdrawPair;
|
||||
BOOST_FOREACH(const WithdrawPair& it, entry.setWithdrawsSpent)
|
||||
assert(mapWithdrawsSpentToTxid.insert(std::make_pair(it, hash)).second);
|
||||
typedef std::pair<uint256, COutPoint> PeginPair;
|
||||
BOOST_FOREACH(const PeginPair& it, entry.setPeginsSpent) {
|
||||
std::pair<std::map<std::pair<uint256, COutPoint>, uint256>::iterator, bool> ret = mapWithdrawsSpentToTxid.insert(std::make_pair(it, hash));
|
||||
assert(ret.second);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -462,9 +464,10 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
|
|||
BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin)
|
||||
mapNextTx.erase(txin.prevout);
|
||||
|
||||
typedef std::pair<uint256, COutPoint> WithdrawPair;
|
||||
BOOST_FOREACH(const WithdrawPair& it2, it->setWithdrawsSpent)
|
||||
assert(mapWithdrawsSpentToTxid.erase(it2));
|
||||
typedef std::pair<uint256, COutPoint> PeginPair;
|
||||
BOOST_FOREACH(const PeginPair& it2, it->setPeginsSpent) {
|
||||
mapWithdrawsSpentToTxid.erase(it2);
|
||||
}
|
||||
|
||||
if (vTxHashes.size() > 1) {
|
||||
vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back());
|
||||
|
|
@ -603,7 +606,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
|
|||
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
|
||||
*/
|
||||
void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight,
|
||||
const std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent)
|
||||
const std::set<std::pair<uint256, COutPoint> >& setPeginsSpent)
|
||||
{
|
||||
LOCK(cs);
|
||||
std::vector<const CTxMemPoolEntry*> entries;
|
||||
|
|
@ -628,7 +631,8 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
|
|||
removeConflicts(*tx);
|
||||
ClearPrioritisation(tx->GetHash());
|
||||
}
|
||||
for (std::set<std::pair<uint256, COutPoint> >::const_iterator it = setWithdrawsSpent.begin(); it != setWithdrawsSpent.end(); it++) {
|
||||
// Eject any conflicting pegins
|
||||
for (std::set<std::pair<uint256, COutPoint> >::const_iterator it = setPeginsSpent.begin(); it != setPeginsSpent.end(); it++) {
|
||||
std::map<std::pair<uint256, COutPoint>, uint256>::const_iterator it2 = mapWithdrawsSpentToTxid.find(*it);
|
||||
if (it2 != mapWithdrawsSpentToTxid.end()) {
|
||||
txiter txit = mapTx.find(it2->second);
|
||||
|
|
@ -679,7 +683,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
|
||||
LOCK(cs);
|
||||
std::list<const CTxMemPoolEntry*> waitingOnDependants;
|
||||
std::set<std::pair<uint256, COutPoint> > setGlobalWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setGlobalPeginsSpent;
|
||||
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
|
||||
unsigned int i = 0;
|
||||
checkTotal += it->GetTxSize();
|
||||
|
|
@ -757,15 +761,15 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
waitingOnDependants.push_back(&(*it));
|
||||
else {
|
||||
CValidationState state;
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
bool fCheckResult = tx.IsCoinBase() ||
|
||||
Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, setWithdrawsSpent, NULL, false);
|
||||
Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, setPeginsSpent, NULL, false);
|
||||
assert(fCheckResult);
|
||||
UpdateCoins(tx, mempoolDuplicate, 1000000);
|
||||
assert(setWithdrawsSpent == it->setWithdrawsSpent);
|
||||
size_t prevWithdrawsCount = setGlobalWithdrawsSpent.size();
|
||||
setGlobalWithdrawsSpent.insert(setWithdrawsSpent.begin(), setWithdrawsSpent.end());
|
||||
assert(setGlobalWithdrawsSpent.size() == prevWithdrawsCount + setWithdrawsSpent.size());
|
||||
assert(setPeginsSpent == it->setPeginsSpent);
|
||||
size_t prevWithdrawsCount = setGlobalPeginsSpent.size();
|
||||
setGlobalPeginsSpent.insert(setPeginsSpent.begin(), setPeginsSpent.end());
|
||||
assert(setGlobalPeginsSpent.size() == prevWithdrawsCount + setPeginsSpent.size());
|
||||
}
|
||||
}
|
||||
unsigned int stepsSinceLastRemove = 0;
|
||||
|
|
@ -778,15 +782,15 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
stepsSinceLastRemove++;
|
||||
assert(stepsSinceLastRemove < waitingOnDependants.size());
|
||||
} else {
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
bool fCheckResult = entry->GetTx().IsCoinBase() ||
|
||||
Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, setWithdrawsSpent, NULL, false);
|
||||
Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, setPeginsSpent, NULL, false);
|
||||
assert(fCheckResult);
|
||||
UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
|
||||
assert(setWithdrawsSpent == entry->setWithdrawsSpent);
|
||||
size_t prevWithdrawsCount = setGlobalWithdrawsSpent.size();
|
||||
setGlobalWithdrawsSpent.insert(setWithdrawsSpent.begin(), setWithdrawsSpent.end());
|
||||
assert(setGlobalWithdrawsSpent.size() == prevWithdrawsCount + setWithdrawsSpent.size());
|
||||
assert(setPeginsSpent == entry->setPeginsSpent);
|
||||
size_t prevWithdrawsCount = setGlobalPeginsSpent.size();
|
||||
setGlobalPeginsSpent.insert(setPeginsSpent.begin(), setPeginsSpent.end());
|
||||
assert(setGlobalPeginsSpent.size() == prevWithdrawsCount + setPeginsSpent.size());
|
||||
stepsSinceLastRemove = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -798,13 +802,13 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
|||
assert(&tx == it->second);
|
||||
}
|
||||
|
||||
for (std::set<std::pair<uint256, COutPoint> >::const_iterator it = setGlobalWithdrawsSpent.begin(); it != setGlobalWithdrawsSpent.end(); it++) {
|
||||
for (std::set<std::pair<uint256, COutPoint> >::const_iterator it = setGlobalPeginsSpent.begin(); it != setGlobalPeginsSpent.end(); it++) {
|
||||
assert(!pcoins->IsWithdrawSpent(*it));
|
||||
}
|
||||
for (std::map<std::pair<uint256, COutPoint>, uint256>::const_iterator it = mapWithdrawsSpentToTxid.begin(); it != mapWithdrawsSpentToTxid.end(); it++) {
|
||||
assert(setGlobalWithdrawsSpent.erase(it->first));
|
||||
assert(setGlobalPeginsSpent.erase(it->first));
|
||||
}
|
||||
assert(setGlobalWithdrawsSpent.size() == 0);
|
||||
assert(setGlobalPeginsSpent.size() == 0);
|
||||
|
||||
assert(totalTxSize == checkTotal);
|
||||
assert(innerUsage == cachedInnerUsage);
|
||||
|
|
|
|||
|
|
@ -112,12 +112,12 @@ private:
|
|||
int64_t nSigOpCostWithAncestors;
|
||||
|
||||
public:
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
||||
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
CAmount _inChainInputValue, bool spendsCoinbase,
|
||||
int64_t nSigOpsCost, LockPoints lp, std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent);
|
||||
int64_t nSigOpsCost, LockPoints lp, std::set<std::pair<uint256, COutPoint> >& setPeginsSpent);
|
||||
|
||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||
|
||||
|
|
@ -544,7 +544,7 @@ public:
|
|||
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
|
||||
void removeConflicts(const CTransaction &tx);
|
||||
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight,
|
||||
const std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent);
|
||||
const std::set<std::pair<uint256, COutPoint> >& setPeginsSpent);
|
||||
void clear();
|
||||
void _clear(); //lock free
|
||||
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
|
||||
|
|
|
|||
|
|
@ -1089,7 +1089,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
{
|
||||
CCoinsView dummy;
|
||||
CCoinsViewCache view(&dummy);
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
|
||||
LockPoints lp;
|
||||
{
|
||||
|
|
@ -1122,24 +1122,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
if (!view.HaveInputs(tx))
|
||||
return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent");
|
||||
|
||||
// We disable replacement of peg-ins as they are spendable-by-anyone
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin)
|
||||
{
|
||||
CCoins coins;
|
||||
bool ret;
|
||||
ret = view.GetCoins(txin.prevout.hash, coins);
|
||||
assert(ret);
|
||||
if (coins.vout[txin.prevout.n].scriptPubKey.IsWithdrawLock() && txin.scriptSig.IsWithdrawProof()) {
|
||||
std::pair<uint256, COutPoint> outpoint = std::make_pair(coins.vout[txin.prevout.n].scriptPubKey.GetWithdrawLockGenesisHash(), txin.scriptSig.GetWithdrawSpent());
|
||||
if (pool.mapNextTx.count(txin.prevout))
|
||||
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-replace-withdraw");
|
||||
|
||||
if (view.IsWithdrawSpent(outpoint))
|
||||
return state.Invalid(false, REJECT_CONFLICT, "withdraw-already-claimed");
|
||||
setWithdrawsSpent.insert(outpoint);
|
||||
}
|
||||
}
|
||||
|
||||
// Bring the best block into scope
|
||||
view.GetBestBlock();
|
||||
|
||||
|
|
@ -1177,8 +1159,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
CAmount inChainInputValue;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
|
||||
|
||||
bool fIsWithdrawLockSpender = false;
|
||||
|
||||
// Keep track of transactions that spend a coinbase, which we re-scan
|
||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||
// Also track withdraw lock spends to allow them through free relay
|
||||
|
|
@ -1189,13 +1169,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
fSpendsCoinbase = true;
|
||||
break;
|
||||
}
|
||||
if (coins->vout[txin.prevout.n].scriptPubKey.IsWithdrawLock()) {
|
||||
fIsWithdrawLockSpender = true;
|
||||
}
|
||||
}
|
||||
|
||||
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(),
|
||||
inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp, setWithdrawsSpent);
|
||||
inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp, setPeginsSpent);
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
// Check that the transaction doesn't have an excessive number of
|
||||
|
|
@ -1212,8 +1189,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
|
||||
}
|
||||
|
||||
// No transactions are allowed below minRelayTxFee except from disconnected blocks and withdraw lock spends
|
||||
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !fIsWithdrawLockSpender)
|
||||
// No transactions are allowed below minRelayTxFee except from disconnected blocks
|
||||
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
|
||||
{
|
||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
|
||||
}
|
||||
|
|
@ -1383,21 +1360,21 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
scriptVerifyFlags = GetArg("-promiscuousmempoolflags", scriptVerifyFlags);
|
||||
}
|
||||
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent2;
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent2;
|
||||
|
||||
// Check against previous transactions
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata, setWithdrawsSpent2)) {
|
||||
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata, setPeginsSpent2)) {
|
||||
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
||||
// need to turn both off, and compare against just turning off CLEANSTACK
|
||||
// to see if the failure is specifically due to witness validation.
|
||||
setWithdrawsSpent2.clear();
|
||||
setPeginsSpent2.clear();
|
||||
CValidationState stateDummy; // Want reported failures to be from first CheckInputs
|
||||
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata, setWithdrawsSpent2)) {
|
||||
setWithdrawsSpent2.clear();
|
||||
if (!CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata, setWithdrawsSpent2)) {
|
||||
setWithdrawsSpent2.clear();
|
||||
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata, setPeginsSpent2)) {
|
||||
setPeginsSpent2.clear();
|
||||
if (!CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata, setPeginsSpent2)) {
|
||||
setPeginsSpent2.clear();
|
||||
// Only the witness is missing, so the transaction itself may be fine.
|
||||
state.SetCorruptionPossible();
|
||||
}
|
||||
|
|
@ -1405,8 +1382,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
return false; // state filled in by CheckInputs
|
||||
}
|
||||
|
||||
assert(setWithdrawsSpent2 == setWithdrawsSpent);
|
||||
setWithdrawsSpent2.clear();
|
||||
assert(setPeginsSpent2 == setPeginsSpent);
|
||||
setPeginsSpent2.clear();
|
||||
|
||||
// Check again against just the consensus-critical mandatory script
|
||||
// verification flags, in case of bugs in the standard flags that cause
|
||||
|
|
@ -1417,13 +1394,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|||
// There is a similar check in CreateNewBlock() to prevent creating
|
||||
// invalid blocks, however allowing such transactions into the mempool
|
||||
// can be exploited as a DoS attack.
|
||||
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, setWithdrawsSpent2))
|
||||
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, setPeginsSpent2))
|
||||
{
|
||||
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
|
||||
__func__, hash.ToString(), FormatStateMessage(state));
|
||||
}
|
||||
|
||||
assert(setWithdrawsSpent2 == setWithdrawsSpent);
|
||||
assert(setPeginsSpent2 == setPeginsSpent);
|
||||
|
||||
// Remove conflicting transactions from the mempool
|
||||
BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting)
|
||||
|
|
@ -1546,145 +1523,6 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
|
|||
return false;
|
||||
}
|
||||
|
||||
bool utxoSort(const std::pair<COutPoint, CAmount>& a, const std::pair<COutPoint, CAmount>& b) {
|
||||
return a.second > b.second;
|
||||
}
|
||||
|
||||
/** Select Inputs which lock at least nAmount to the given chain */
|
||||
bool GetLockedOutputs(const uint256 &genesisHash, const CAmount &nAmount, std::vector<std::pair<COutPoint, CAmount> >& res) {
|
||||
res.clear();
|
||||
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
|
||||
std::vector<std::pair<COutPoint, CAmount> > locksCreated;
|
||||
bool locksChanged = false;
|
||||
// If this fails, we should still try to grab from mempool.
|
||||
if (!pblocktree->ReadLocksCreated(genesisHash, locksCreated)) {
|
||||
locksCreated.clear();
|
||||
}
|
||||
|
||||
//For faster random esasure
|
||||
std::list<std::pair<COutPoint, CAmount> > locksList;
|
||||
std::copy(locksCreated.begin(), locksCreated.end(), std::back_inserter(locksList));
|
||||
|
||||
unsigned int skippedLocks = 0;
|
||||
while (locksList.size() - skippedLocks > 0) {
|
||||
uint64_t idx = GetRand(locksList.size() - skippedLocks);
|
||||
std::list<std::pair<COutPoint, CAmount> >::iterator it = locksList.begin();
|
||||
std::advance(it, idx);
|
||||
const std::pair<COutPoint, CAmount> &lock = (*it);
|
||||
//Should run this first
|
||||
//Erase locks that have been spent in an active block
|
||||
CCoins coins;
|
||||
if (!pcoinsTip->GetCoins(lock.first.hash, coins) || !coins.IsAvailable(lock.first.n)) {
|
||||
locksList.erase(it);
|
||||
locksChanged = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Move too-small locks or locks currently spent in mempool to back of list
|
||||
if (lock.second < nAmount ||
|
||||
mempool.mapNextTx.count(COutPoint(lock.first.hash, lock.first.n))) {
|
||||
locksList.push_back(lock);
|
||||
locksList.erase(it);
|
||||
skippedLocks++;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(coins.vout[lock.first.n].nValue.IsExplicit() && coins.vout[lock.first.n].nValue.GetAmount() == lock.second);
|
||||
res.push_back(lock);
|
||||
break;
|
||||
}
|
||||
if (locksChanged) {
|
||||
//Convert back for serialization
|
||||
std::vector<std::pair<COutPoint, CAmount> > vChangedLocks(locksList.begin(), locksList.end());
|
||||
pblocktree->ReWriteLocksCreated(genesisHash, vChangedLocks);
|
||||
}
|
||||
//Found single lock large enough
|
||||
if (res.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CAmount nTotal = 0;
|
||||
//Gather up smaller locked outputs for aggregation.
|
||||
for (std::list<std::pair<COutPoint, CAmount> >::iterator it = locksList.begin(); it != locksList.end(); it++) {
|
||||
CCoins coins;
|
||||
if (!pcoinsTip->GetCoins(it->first.hash, coins) || !coins.IsAvailable(it->first.n)) {
|
||||
it = locksList.erase(it);
|
||||
it--;
|
||||
locksChanged = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mempool.mapNextTx.count(COutPoint(it->first.hash, it->first.n))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(coins.vout[it->first.n].nValue.IsExplicit() && coins.vout[it->first.n].nValue.GetAmount() == it->second);
|
||||
res.push_back(*it);
|
||||
|
||||
nTotal += it->second;
|
||||
assert(MoneyRange(nTotal));
|
||||
}
|
||||
|
||||
if (locksChanged) {
|
||||
//Convert back for serialization
|
||||
std::vector<std::pair<COutPoint, CAmount> > vChangedLocks(locksList.begin(), locksList.end());
|
||||
pblocktree->ReWriteLocksCreated(genesisHash, vChangedLocks);
|
||||
}
|
||||
|
||||
//If not enough, combine mempool locks
|
||||
if (nTotal < nAmount) {
|
||||
std::vector<const CTransaction*> vMempoolTxn;
|
||||
BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) {
|
||||
vMempoolTxn.push_back(&e.GetTx());
|
||||
}
|
||||
|
||||
std::random_shuffle(vMempoolTxn.begin(), vMempoolTxn.end());
|
||||
|
||||
BOOST_FOREACH(const CTransaction* ptx, vMempoolTxn) {
|
||||
const CTransaction& tx = *ptx;
|
||||
for (unsigned int j = 0; j < tx.vout.size() && nTotal < nAmount; j++) {
|
||||
CTxOut txout = tx.vout[j];
|
||||
if (!txout.scriptPubKey.IsWithdrawLock()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint256 withdrawGenHash = txout.scriptPubKey.GetWithdrawLockGenesisHash();
|
||||
if (genesisHash != withdrawGenHash) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only written locks are filtered previously for invalid type
|
||||
if (txout.nValue.IsCommitment() || txout.nAsset.IsCommitment() || txout.nAsset.GetAsset() != Params().GetConsensus().pegged_asset) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mempool.mapNextTx.count(COutPoint(tx.GetHash(), j))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
res.push_back(std::make_pair(COutPoint(tx.GetHash(), j), txout.nValue.GetAmount()));
|
||||
nTotal += txout.nValue.GetAmount();
|
||||
if (nTotal >= nAmount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//res list is already randomized
|
||||
nTotal = 0;
|
||||
size_t i = 0;
|
||||
for (; i < res.size() && nTotal < nAmount; i++) {
|
||||
nTotal += res[i].second;
|
||||
}
|
||||
|
||||
res.resize(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CBlock and CBlockIndex
|
||||
|
|
@ -1921,11 +1759,6 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
|
|||
if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull())
|
||||
assert(false);
|
||||
|
||||
if (coins->vout[txin.prevout.n].scriptPubKey.IsWithdrawLock() && txin.scriptSig.IsWithdrawProof()) {
|
||||
std::pair<uint256, COutPoint> outpoint = std::make_pair(coins->vout[txin.prevout.n].scriptPubKey.GetWithdrawLockGenesisHash(), txin.scriptSig.GetWithdrawSpent());
|
||||
inputs.SetWithdrawSpent(outpoint, true);
|
||||
}
|
||||
|
||||
// mark an outpoint spent, and construct undo information
|
||||
txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos]));
|
||||
coins->Spend(nPos);
|
||||
|
|
@ -1950,7 +1783,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
|
|||
bool CScriptCheck::operator()() {
|
||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, amountPreviousInput, Params().GetConsensus().fedpegScript, cacheStore, *txdata), &error)) {
|
||||
if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1964,7 +1797,7 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
|
|||
}
|
||||
|
||||
namespace Consensus {
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore)
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, std::set<std::pair<uint256, COutPoint> >& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore)
|
||||
{
|
||||
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
|
||||
// for an attacker to attempt to split the network.
|
||||
|
|
@ -1994,17 +1827,6 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
|||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
|
||||
}
|
||||
|
||||
if (coins->vout[prevout.n].scriptPubKey.IsWithdrawLock() && tx.vin[i].scriptSig.IsWithdrawProof()) {
|
||||
uint256 genesisHash(coins->vout[prevout.n].scriptPubKey.GetWithdrawLockGenesisHash());
|
||||
COutPoint withdrawSpent(tx.vin[i].scriptSig.GetWithdrawSpent());
|
||||
std::pair<uint256, COutPoint> withdraw = std::make_pair(genesisHash, withdrawSpent);
|
||||
if (inputs.IsWithdrawSpent(withdraw))
|
||||
return state.Invalid(false, REJECT_INVALID, "bad-txns-double-withdraw", strprintf("Double-withdraw of %s:%d", withdrawSpent.hash.ToString(), withdrawSpent.n));
|
||||
if (setWithdrawsSpent.count(withdraw))
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-double-withdraw-in-obj", false,
|
||||
strprintf("Double-withdraw of %s:%d in single tx/block", withdrawSpent.hash.ToString(), withdrawSpent.n));
|
||||
setWithdrawsSpent.insert(withdraw);
|
||||
}
|
||||
}
|
||||
|
||||
// Tally transaction fees
|
||||
|
|
@ -2018,11 +1840,11 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
|||
}
|
||||
}// namespace Consensus
|
||||
|
||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent, std::vector<CCheck*> *pvChecks)
|
||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::set<std::pair<uint256, COutPoint> >& setPeginsSpent, std::vector<CCheck*> *pvChecks)
|
||||
{
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), setWithdrawsSpent, pvChecks, cacheStore))
|
||||
if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs), setPeginsSpent, pvChecks, cacheStore))
|
||||
return false;
|
||||
|
||||
if (pvChecks)
|
||||
|
|
@ -2038,14 +1860,13 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
// Of course, if an assumed valid block is invalid due to false scriptSigs
|
||||
// this optimization would allow an invalid chain to be accepted.
|
||||
if (fScriptChecks) {
|
||||
CAmount prevValueIn = -1;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins* coins = inputs.AccessCoins(prevout.hash);
|
||||
assert(coins);
|
||||
|
||||
// Verify signature
|
||||
CCheck* check = new CScriptCheck(*coins, tx, i, prevValueIn, flags, cacheStore, &txdata);
|
||||
CCheck* check = new CScriptCheck(*coins, tx, i, flags, cacheStore, &txdata);
|
||||
ScriptError serror = QueueCheck(pvChecks, check);
|
||||
if (serror != SCRIPT_ERR_OK) {
|
||||
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) {
|
||||
|
|
@ -2055,7 +1876,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
// arguments; if so, don't trigger DoS protection to
|
||||
// avoid splitting the network between upgraded and
|
||||
// non-upgraded nodes.
|
||||
CScriptCheck check2(*coins, tx, i, prevValueIn,
|
||||
CScriptCheck check2(*coins, tx, i,
|
||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
|
||||
if (check2())
|
||||
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(serror)));
|
||||
|
|
@ -2067,16 +1888,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||
// as to the correct behavior - we may want to continue
|
||||
// peering with non-upgraded nodes even after soft-fork
|
||||
// super-majority signaling has occurred.
|
||||
if (serror == SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED)
|
||||
return state.Invalid(false, REJECT_SCRIPT, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(serror)));
|
||||
else
|
||||
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(serror)));
|
||||
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(serror)));
|
||||
}
|
||||
const CConfidentialValue& value = coins->vout[tx.vin[i].prevout.n].nValue;
|
||||
if (value.IsExplicit())
|
||||
prevValueIn = value.GetAmount();
|
||||
else
|
||||
prevValueIn = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2192,20 +2005,6 @@ bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const COutPoint
|
|||
coins->vout.resize(out.n+1);
|
||||
coins->vout[out.n] = undo.txout;
|
||||
|
||||
if (undo.txout.scriptPubKey.IsWithdrawLock()) {
|
||||
if (!txin.scriptSig.IsWithdrawProof()) {
|
||||
if (!txin.scriptSig.IsPushOnly())
|
||||
fClean = fClean && error("%s: lock spent by non-proof", __func__);
|
||||
} else {
|
||||
std::pair<uint256, COutPoint> outpoint = std::make_pair(undo.txout.scriptPubKey.GetWithdrawLockGenesisHash(), txin.scriptSig.GetWithdrawSpent());
|
||||
bool fSpent = view.IsWithdrawSpent(outpoint);
|
||||
if (!fSpent)
|
||||
fClean = fClean && error("%s: withdraw not marked spent", __func__);
|
||||
else
|
||||
view.SetWithdrawSpent(outpoint, false);
|
||||
}
|
||||
}
|
||||
|
||||
return fClean;
|
||||
}
|
||||
|
||||
|
|
@ -2458,7 +2257,7 @@ static int64_t nTimeIndex = 0;
|
|||
static int64_t nTimeCallbacks = 0;
|
||||
static int64_t nTimeTotal = 0;
|
||||
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, std::set<std::pair<uint256, COutPoint> >* setWithdrawsSpent, bool fJustCheck)
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, std::set<std::pair<uint256, COutPoint> >* setPeginsSpent, bool fJustCheck)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
|
|
@ -2481,19 +2280,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
CTxUndo undoDummy;
|
||||
UpdateCoins(tx, view, undoDummy, pindex->nHeight);
|
||||
|
||||
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
|
||||
vPos.push_back(std::make_pair(tx.GetHash(), pos));
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
CTxOut txout= tx.vout[i];
|
||||
if (txout.scriptPubKey.IsWithdrawLock() && txout.nValue.IsExplicit() && txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == Params().GetConsensus().pegged_asset)
|
||||
mLocksCreated.insert(std::make_pair(txout.scriptPubKey.GetWithdrawLockGenesisHash(), std::make_pair(COutPoint(tx.GetHash(), i), txout.nValue.GetAmount())));
|
||||
}
|
||||
|
||||
if (fTxIndex)
|
||||
if (!pblocktree->WriteTxIndex(vPos))
|
||||
return AbortNode(state, "Failed to write transaction index");
|
||||
pblocktree->WriteLocksCreated(mLocksCreated);
|
||||
|
||||
view.SetBestBlock(pindex->GetBlockHash());
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2596,9 +2382,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
flags |= SCRIPT_VERIFY_NULLDUMMY;
|
||||
}
|
||||
|
||||
//Enforce WITHDRAWPROOFVERIFY
|
||||
flags |= SCRIPT_VERIFY_WITHDRAW;
|
||||
|
||||
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
|
||||
LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
|
||||
|
||||
|
|
@ -2613,12 +2396,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
|
||||
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
|
||||
vPos.reserve(block.vtx.size());
|
||||
std::multimap<uint256, std::pair<COutPoint, CAmount> > mLocksCreated;
|
||||
blockundo.vtxundo.reserve(block.vtx.size() - 1);
|
||||
std::vector<PrecomputedTransactionData> txdata;
|
||||
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
|
||||
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpentDummy;
|
||||
// Used when ConnectBlock() results are unneeded for mempool ejection
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpentDummy;
|
||||
|
||||
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||
{
|
||||
|
|
@ -2660,9 +2443,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
{
|
||||
std::vector<CCheck*> vChecks;
|
||||
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
|
||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], setWithdrawsSpent == NULL ? setWithdrawsSpentDummy : *setWithdrawsSpent, nScriptCheckThreads ? &vChecks : NULL))
|
||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], setPeginsSpent == NULL ? setPeginsSpentDummy : *setPeginsSpent, nScriptCheckThreads ? &vChecks : NULL)) {
|
||||
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
||||
tx.GetHash().ToString(), FormatStateMessage(state));
|
||||
}
|
||||
control.Add(vChecks);
|
||||
}
|
||||
|
||||
|
|
@ -2675,12 +2459,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
vPos.push_back(std::make_pair(tx.GetHash(), pos));
|
||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
for (unsigned int j = 0; j < tx.vout.size(); j++) {
|
||||
CTxOut txout = tx.vout[j];
|
||||
if (txout.scriptPubKey.IsWithdrawLock() && txout.nValue.IsExplicit() && txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == Params().GetConsensus().pegged_asset) {
|
||||
mLocksCreated.insert(std::make_pair(txout.scriptPubKey.GetWithdrawLockGenesisHash(), std::make_pair(COutPoint(tx.GetHash(), j), txout.nValue.GetAmount())));
|
||||
}
|
||||
}
|
||||
if (!tx.HasValidFee())
|
||||
return state.DoS(100, error("ConnectBlock(): transaction fee overflowed"), REJECT_INVALID, "bad-fee-outofrange");
|
||||
mapFees += tx.GetFee();
|
||||
|
|
@ -2699,9 +2477,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
blockReward[policyAsset]),
|
||||
REJECT_INVALID, "bad-cb-amount");
|
||||
|
||||
//Don't DoS ban in case of RPC script check failure
|
||||
if (!control.Wait())
|
||||
return state.Invalid(false, REJECT_SCRIPT);
|
||||
return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
|
||||
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
|
||||
LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);
|
||||
|
||||
|
|
@ -2731,8 +2508,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
|||
if (!pblocktree->WriteTxIndex(vPos))
|
||||
return AbortNode(state, "Failed to write transaction index");
|
||||
|
||||
pblocktree->WriteLocksCreated(mLocksCreated);
|
||||
|
||||
// add this block to the view's block chain
|
||||
view.SetBestBlock(pindex->GetBlockHash());
|
||||
|
||||
|
|
@ -3030,34 +2805,16 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
|||
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
|
||||
int64_t nTime3;
|
||||
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
// For mempool removal with pegin conflicts
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
{
|
||||
CCoinsViewCache view(pcoinsTip);
|
||||
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams, &setWithdrawsSpent);
|
||||
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams, &setPeginsSpent);
|
||||
GetMainSignals().BlockChecked(blockConnecting, state);
|
||||
if (!rv) {
|
||||
if (state.IsInvalid()) {
|
||||
InvalidBlockFound(pindexNew, state);
|
||||
//Possibly result of RPC to bitcoind failure
|
||||
//or unseen Bitcoin blocks.
|
||||
if (state.GetRejectCode() == REJECT_SCRIPT) {
|
||||
//Write queue of invalid blocks that
|
||||
//must be cleared to continue operation
|
||||
std::vector<uint256> vinvalidBlocks;
|
||||
pblocktree->ReadInvalidBlockQueue(vinvalidBlocks);
|
||||
bool blockAlreadyInvalid = false;
|
||||
BOOST_FOREACH(uint256& hash, vinvalidBlocks) {
|
||||
if (hash == pblock->GetHash()) {
|
||||
blockAlreadyInvalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blockAlreadyInvalid) {
|
||||
vinvalidBlocks.push_back(pblock->GetHash());
|
||||
pblocktree->WriteInvalidBlockQueue(vinvalidBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
|
||||
}
|
||||
|
|
@ -3074,7 +2831,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
|||
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
|
||||
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
|
||||
// Remove conflicting transactions from the mempool.;
|
||||
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight, setWithdrawsSpent);
|
||||
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight, setPeginsSpent);
|
||||
// Update chainActive & related variables.
|
||||
UpdateTip(pindexNew, chainparams);
|
||||
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
|
|||
* instead of being performed inline.
|
||||
*/
|
||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
|
||||
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent,
|
||||
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::set<std::pair<uint256, COutPoint> >& setPeginsSpent,
|
||||
std::vector<CCheck*> *pvChecks = NULL);
|
||||
|
||||
/** Apply the effects of this transaction on the UTXO set represented by view */
|
||||
|
|
@ -388,7 +388,7 @@ namespace Consensus {
|
|||
* This does not modify the UTXO set. This does not check scripts and sigs.
|
||||
* Preconditions: tx.IsCoinBase() is false.
|
||||
*/
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, std::set<std::pair<uint256, COutPoint> >& setWithdrawsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore);
|
||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, std::set<std::pair<uint256, COutPoint> >& setPeginsSpent, std::vector<CCheck*> *pvChecks, const bool cacheStore);
|
||||
|
||||
} // namespace Consensus
|
||||
|
||||
|
|
@ -478,7 +478,6 @@ class CScriptCheck : public CCheck
|
|||
private:
|
||||
CScript scriptPubKey;
|
||||
CConfidentialValue amount;
|
||||
CConfidentialValue amountPreviousInput;
|
||||
const CTransaction *ptxTo;
|
||||
unsigned int nIn;
|
||||
unsigned int nFlags;
|
||||
|
|
@ -486,9 +485,8 @@ private:
|
|||
PrecomputedTransactionData *txdata;
|
||||
|
||||
public:
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, const CConfidentialValue& amountPreviousInputIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
|
||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
|
||||
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
|
||||
amountPreviousInput(amountPreviousInputIn),
|
||||
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn) { }
|
||||
|
||||
bool operator()();
|
||||
|
|
@ -517,7 +515,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
|||
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
|
||||
* can fail if those validity checks fail (among other reasons). */
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins,
|
||||
const CChainParams& chainparams, std::set<std::pair<uint256, COutPoint> >* setWithdrawsSpent = NULL, bool fJustCheck = false);
|
||||
const CChainParams& chainparams, std::set<std::pair<uint256, COutPoint> >* setPeginsSpent = NULL, bool fJustCheck = false);
|
||||
|
||||
/** Undo the effects of this block (with given index) on the UTXO set represented by coins.
|
||||
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
|
||||
|
|
|
|||
|
|
@ -3388,390 +3388,6 @@ public:
|
|||
static CSecp256k1Init instance_of_csecp256k1;
|
||||
}
|
||||
|
||||
CScriptID calculate_contract(const CScript& federationRedeemScript, const CBitcoinAddress& destAddress, const unsigned char nonce[16], unsigned char fullcontract[40]) {
|
||||
fullcontract[0] = (unsigned char)'P';
|
||||
fullcontract[1] = (unsigned char)'2';
|
||||
if (destAddress.IsScript())
|
||||
fullcontract[2] = (unsigned char)'S';
|
||||
else
|
||||
fullcontract[2] = (unsigned char)'P';
|
||||
fullcontract[3] = (unsigned char)'H';
|
||||
memcpy(fullcontract + 4, nonce, 16);
|
||||
|
||||
std::vector<unsigned char> destHash;
|
||||
CScript destScript = GetScriptForDestination(destAddress.Get());
|
||||
CScript::iterator scriptIt = destScript.begin();
|
||||
opcodetype opcodeTmp;
|
||||
assert(destScript.GetOp(scriptIt, opcodeTmp, destHash));
|
||||
if (!destAddress.IsScript()) {
|
||||
assert(opcodeTmp == OP_DUP);
|
||||
assert(destScript.GetOp(scriptIt, opcodeTmp, destHash));
|
||||
}
|
||||
assert(opcodeTmp == OP_HASH160);
|
||||
assert(destScript.GetOp(scriptIt, opcodeTmp, destHash));
|
||||
assert(opcodeTmp == 0x14 && destHash.size() == 20);
|
||||
memcpy(fullcontract + 4 + 16, &destHash[0], destHash.size());
|
||||
|
||||
CScript scriptDestination(federationRedeemScript);
|
||||
{
|
||||
CScript::iterator sdpc = scriptDestination.begin();
|
||||
vector<unsigned char> vch;
|
||||
while (scriptDestination.GetOp(sdpc, opcodeTmp, vch))
|
||||
{
|
||||
assert((vch.size() == 33 && opcodeTmp < OP_PUSHDATA4) ||
|
||||
(opcodeTmp <= OP_16 && opcodeTmp >= OP_1) || opcodeTmp == OP_CHECKMULTISIG);
|
||||
if (vch.size() == 33)
|
||||
{
|
||||
unsigned char tweak[32];
|
||||
size_t pub_len = 33;
|
||||
int ret;
|
||||
unsigned char *pub_start = &(*(sdpc - pub_len));
|
||||
CHMAC_SHA256(pub_start, pub_len).Write(fullcontract, 40).Finalize(tweak);
|
||||
secp256k1_pubkey watchman;
|
||||
secp256k1_pubkey tweaked;
|
||||
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx, &watchman, pub_start, pub_len);
|
||||
assert(ret == 1);
|
||||
ret = secp256k1_ec_pubkey_parse(secp256k1_ctx, &tweaked, pub_start, pub_len);
|
||||
assert(ret == 1);
|
||||
// If someone creates a tweak that makes this fail, they broke SHA256
|
||||
ret = secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, &tweaked, tweak);
|
||||
assert(ret == 1);
|
||||
ret = secp256k1_ec_pubkey_serialize(secp256k1_ctx, pub_start, &pub_len, &tweaked, SECP256K1_EC_COMPRESSED);
|
||||
assert(ret == 1);
|
||||
assert(pub_len == 33);
|
||||
|
||||
// Sanity checks to reduce pegin risk. If the tweaked
|
||||
// value flips a bit, we may lose pegin funds irretrievably.
|
||||
// We take the tweak, derive its pubkey and check that
|
||||
// `tweaked - watchman = tweak` to check the computation
|
||||
// two different ways
|
||||
secp256k1_pubkey tweaked2;
|
||||
ret = secp256k1_ec_pubkey_create(secp256k1_ctx, &tweaked2, tweak);
|
||||
assert(ret);
|
||||
ret = secp256k1_ec_pubkey_negate(secp256k1_ctx, &watchman);
|
||||
assert(ret);
|
||||
secp256k1_pubkey* pubkey_combined[2];
|
||||
pubkey_combined[0] = &watchman;
|
||||
pubkey_combined[1] = &tweaked;
|
||||
secp256k1_pubkey maybe_tweaked2;
|
||||
ret = secp256k1_ec_pubkey_combine(secp256k1_ctx, &maybe_tweaked2, pubkey_combined, 2);
|
||||
assert(ret);
|
||||
assert(!memcmp(&maybe_tweaked2, &tweaked2, 64));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CScriptID(scriptDestination);
|
||||
}
|
||||
|
||||
UniValue getpeginaddress(const JSONRPCRequest& request)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(request.fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (request.fHelp || request.params.size() > 1)
|
||||
throw std::runtime_error(
|
||||
"getpeginaddress ( \"account\" )\n"
|
||||
"\nReturns information needed for claimpegin to move coins to the sidechain.\n"
|
||||
"The user should send coins from their Bitcoin wallet to the mainchain_address returned.\n"
|
||||
"IMPORTANT: Like getaddress, getpeginaddress adds new secrets to wallet.dat, necessitating backup on a regular basis.\n"
|
||||
|
||||
"\nArguments:\n"
|
||||
"1. \"account\" (string, optional) The account name for the address to be linked to. if not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
|
||||
"\nResult:\n"
|
||||
"\"mainchain_address\" (string) Mainchain Bitcoin deposit address to send bitcoin to\n"
|
||||
"\"sidechain_address\" (string) The sidechain address in this wallet which must be used in `claimpegin` to retrieve pegged-in funds\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getpeginaddress", "")
|
||||
+ HelpExampleCli("getpeginaddress", "\"\"")
|
||||
+ HelpExampleCli("getpeginaddress", "\"myaccount\"")
|
||||
+ HelpExampleRpc("getpeginaddress", "\"myaccount\"")
|
||||
);
|
||||
|
||||
//Creates new address for receiving unlocked utxos
|
||||
CBitcoinAddress address(CBitcoinAddress(getnewaddress(request).get_str()).GetUnblinded());
|
||||
|
||||
//Call contracthashtool, get deposit address on mainchain.
|
||||
unsigned char nonce[16];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
unsigned char fullcontract[40];
|
||||
CParentBitcoinAddress destAddr(calculate_contract(Params().GetConsensus().fedpegScript, address, nonce, fullcontract));
|
||||
|
||||
UniValue fundinginfo(UniValue::VOBJ);
|
||||
|
||||
AuditLogPrintf("%s : getpeginaddress mainchain_address: %s sidechain_address: %s\n", getUser(), destAddr.ToString(), address.ToString());
|
||||
|
||||
fundinginfo.pushKV("mainchain_address", destAddr.ToString());
|
||||
fundinginfo.pushKV("sidechain_address", address.ToString());
|
||||
return fundinginfo;
|
||||
}
|
||||
|
||||
UniValue sendtomainchain(const JSONRPCRequest& request)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(request.fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (request.fHelp || request.params.size() != 2)
|
||||
throw runtime_error(
|
||||
"sendtomainchain mainchainaddress amount\n"
|
||||
"\nSends sidechain funds to the given mainchain address, through the federated withdraw mechanism\n"
|
||||
+ HelpRequiringPassphrase() +
|
||||
"\nArguments:\n"
|
||||
"1. \"address\" (string, required) The destination address on Bitcoin mainchain\n"
|
||||
"2. \"amount\" (numeric, required) The amount being sent to Bitcoin mainchain\n"
|
||||
"\nResult:\n"
|
||||
"\"txid\" (string) Transaction ID of the resulting sidechain transaction\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("sendtomainchain", "\"mgWEy4vBJSHt3mC8C2SEWJQitifb4qeZQq\" 0.1")
|
||||
+ HelpExampleRpc("sendtomainchain", "\"mgWEy4vBJSHt3mC8C2SEWJQitifb4qeZQq\" 0.1")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
CParentBitcoinAddress address(request.params[0].get_str());
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
|
||||
CAmount nAmount = AmountFromValue(request.params[1]);
|
||||
if (nAmount <= 0)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
|
||||
|
||||
// Parse Bitcoin address for asm field
|
||||
CScript scriptPubKeyMainchain(GetScriptForDestination(address.Get()));
|
||||
CScript::const_iterator pc(scriptPubKeyMainchain.begin());
|
||||
CScript::const_iterator pend(scriptPubKeyMainchain.end());
|
||||
opcodetype type;
|
||||
vector<unsigned char> vData;
|
||||
while (pc != pend) {
|
||||
scriptPubKeyMainchain.GetOp(pc, type, vData);
|
||||
if (type == OP_HASH160) {
|
||||
scriptPubKeyMainchain.GetOp(pc, type, vData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(pc != pend && type == 0x14);
|
||||
|
||||
CScript scriptPubKey;
|
||||
|
||||
vector<unsigned char> hex;
|
||||
hex.push_back((unsigned char)'P');
|
||||
hex.push_back((unsigned char)'2');
|
||||
if (scriptPubKeyMainchain.IsPayToScriptHash())
|
||||
hex.push_back((unsigned char)'S');
|
||||
else
|
||||
hex.push_back((unsigned char)'P');
|
||||
hex.push_back((unsigned char)'H');
|
||||
hex.insert(hex.end(), vData.begin(), vData.end());
|
||||
|
||||
uint256 genesisBlockHash = Params().ParentGenesisBlockHash();
|
||||
|
||||
scriptPubKey << hex;
|
||||
scriptPubKey << OP_DROP;
|
||||
scriptPubKey << std::vector<unsigned char>(genesisBlockHash.begin(), genesisBlockHash.end());
|
||||
scriptPubKey << OP_WITHDRAWPROOFVERIFY;
|
||||
assert(scriptPubKey.IsWithdrawLock());
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
CWalletTx wtxNew;
|
||||
SendMoney(scriptPubKey, nAmount, Params().GetConsensus().pegged_asset, false, CPubKey(), wtxNew, true);
|
||||
|
||||
std::string blinds;
|
||||
for (unsigned int i=0; i<wtxNew.tx->vout.size(); i++) {
|
||||
blinds += "blind:" + wtxNew.GetOutputBlindingFactor(i).ToString() + "\n";
|
||||
}
|
||||
|
||||
AuditLogPrintf("%s : sendtomainchain %s\nblinds:\n%s\n", getUser(), wtxNew.tx->GetHash().GetHex(), blinds);
|
||||
|
||||
return wtxNew.GetHash().GetHex();
|
||||
}
|
||||
|
||||
extern UniValue sendrawtransaction(const JSONRPCRequest& request);
|
||||
|
||||
unsigned int GetPeginTxnOutputIndex(const Sidechain::Bitcoin::CTransaction& txn, const CBitcoinAddress& sidechainAddress, unsigned char* fullcontract)
|
||||
{
|
||||
unsigned char nonce[16];
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
unsigned int nOut = 0;
|
||||
//Call contracthashtool
|
||||
CScript mainchain_script = GetScriptForDestination(calculate_contract(Params().GetConsensus().fedpegScript, sidechainAddress, &nonce[0], fullcontract));
|
||||
for (; nOut < txn.vout.size(); nOut++)
|
||||
if (txn.vout[nOut].scriptPubKey == mainchain_script)
|
||||
break;
|
||||
return nOut;
|
||||
}
|
||||
|
||||
UniValue claimpegin(const JSONRPCRequest& request)
|
||||
{
|
||||
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
|
||||
throw std::runtime_error(
|
||||
"claimpegin bitcoinTx txoutproof ( sidechain_address )\n"
|
||||
"\nClaim coins from the main chain by creating a withdraw transaction with the necessary metadata after the corresponding Bitcoin transaction.\n"
|
||||
"Note that the transaction will not be relayed unless it is buried at least 102 blocks deep.\n"
|
||||
"If a transaction is not relayed it may require manual addition to a functionary mempool in order for it to be mined.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"bitcoinTx\" (string, required) The raw bitcoin transaction (in hex) depositing bitcoin to the mainchain_address generated by getpeginaddress\n"
|
||||
"2. \"txoutproof\" (string, required) A rawtxoutproof (in hex) generated by bitcoind's `gettxoutproof` containing a proof of only bitcoinTx\n"
|
||||
"3. \"sidechain_address\" (string, optional) The sidechain_address generated by getpeginaddress. Only needed if not in wallet.\n"
|
||||
"\nResult:\n"
|
||||
"\"txid\" (string) Txid of the resulting sidechain transaction\n"
|
||||
"\nExamples:\n"
|
||||
//XXX: Fix the examples
|
||||
+ HelpExampleCli("claimpegin", "\"2NEqRzqBst5rWrVx7SpwG37T17mvehLhKaN\", \"010000000151ef48c69a67700e6b30a4413eda4b631802c4514d7a09971dc12c703917e39f000000006c4730440220158c57dc3e80a826e4e348b7f530a9a9a3bb6b2913b089c03d08d0bdbf4e0d5b02201a8acf14cecbb74373894816fa69efa96e8f4e0ca633dcf99c99251200149c7b8323210214fd9d286f6aa8a7bdd043b1d5f3e3cdf754e9f1e50b65e5648704b01b2febb0acffffffff0100000000000000000000000000\" \"d50c8eec366e98b258414509d88e72ed0d2b24f63256e076d2b9d0ac3d55abc1\"")
|
||||
+ HelpExampleRpc("claimpegin", "\"2NEqRzqBst5rWrVx7SpwG37T17mvehLhKaN\", \"010000000151ef48c69a67700e6b30a4413eda4b631802c4514d7a09971dc12c703917e39f000000006c4730440220158c57dc3e80a826e4e348b7f530a9a9a3bb6b2913b089c03d08d0bdbf4e0d5b02201a8acf14cecbb74373894816fa69efa96e8f4e0ca633dcf99c99251200149c7b8323210214fd9d286f6aa8a7bdd043b1d5f3e3cdf754e9f1e50b65e5648704b01b2febb0acffffffff0100000000000000000000000000\", \"d50c8eec366e98b258414509d88e72ed0d2b24f63256e076d2b9d0ac3d55abc1\"")
|
||||
);
|
||||
|
||||
if (IsInitialBlockDownload()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Peg-ins cannot be completed during initial sync or reindexing.");
|
||||
}
|
||||
|
||||
if (!IsHex(request.params[0].get_str()) || !IsHex(request.params[1].get_str())) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "the first two arguments must be hex strings");
|
||||
}
|
||||
|
||||
|
||||
std::vector<unsigned char> txData = ParseHex(request.params[0].get_str());
|
||||
CDataStream ssTx(txData, SER_NETWORK, PROTOCOL_VERSION);
|
||||
Sidechain::Bitcoin::CTransactionRef txBTCRef;
|
||||
try {
|
||||
ssTx >> txBTCRef;
|
||||
}
|
||||
catch (...) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "The included bitcoinTx is malformed. Are you sure that is the whole string?");
|
||||
}
|
||||
Sidechain::Bitcoin::CTransaction txBTC(*txBTCRef);
|
||||
|
||||
std::vector<unsigned char> txOutProofData = ParseHex(request.params[1].get_str());
|
||||
CDataStream ssTxOutProof(txOutProofData, SER_NETWORK, PROTOCOL_VERSION);
|
||||
Sidechain::Bitcoin::CMerkleBlock merkleBlock;
|
||||
try {
|
||||
ssTxOutProof >> merkleBlock;
|
||||
}
|
||||
catch (...) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "The included txoutproof is malformed. Are you sure that is the whole string?");
|
||||
}
|
||||
|
||||
if (!ssTxOutProof.empty() || !CheckBitcoinProof(merkleBlock.header.GetHash(), merkleBlock.header.nBits))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof");
|
||||
|
||||
vector<uint256> txHashes;
|
||||
vector<unsigned int> txIndices;
|
||||
if (merkleBlock.txn.ExtractMatches(txHashes, txIndices) != merkleBlock.header.hashMerkleRoot)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof");
|
||||
|
||||
if (txHashes.size() != 1 || txHashes[0] != txBTC.GetHash())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "The txoutproof must contain bitcoinTx and only bitcoinTx");
|
||||
|
||||
unsigned int nOut = 0;
|
||||
unsigned char fullcontract[40];
|
||||
CBitcoinAddress sidechainAddress;
|
||||
if (request.params.size() > 2) {
|
||||
sidechainAddress = CBitcoinAddress(request.params[2].get_str());
|
||||
if (!sidechainAddress.IsValid()) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Given sidechain_address is invalid.");
|
||||
}
|
||||
nOut = GetPeginTxnOutputIndex(txBTC, sidechainAddress, fullcontract);
|
||||
}
|
||||
else {
|
||||
// Look through address book for pegin contract value
|
||||
for (std::map<CTxDestination, CAddressBookData>::const_iterator iter = pwalletMain->mapAddressBook.begin(); iter != pwalletMain->mapAddressBook.end(); ++iter) {
|
||||
sidechainAddress = CBitcoinAddress(iter->first);
|
||||
nOut = GetPeginTxnOutputIndex(txBTC, sidechainAddress, fullcontract);
|
||||
if (nOut != txBTC.vout.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nOut == txBTC.vout.size())
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to find output in bitcoinTx to the mainchain_address from getpeginaddress");
|
||||
CAmount value = txBTC.vout[nOut].nValue;
|
||||
|
||||
uint256 genesisBlockHash = Params().ParentGenesisBlockHash();
|
||||
|
||||
//Output we're re-locking
|
||||
CScript relock_spk;
|
||||
relock_spk << std::vector<unsigned char>(genesisBlockHash.begin(), genesisBlockHash.end());
|
||||
relock_spk << OP_WITHDRAWPROOFVERIFY;
|
||||
|
||||
if (value > MAX_MONEY / 200)
|
||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "IsStandard rules prevent pegging-in > 0.105 million BTC reliably at a time - please work with your functionary to mine a large lock-merge transaction first");
|
||||
|
||||
//Pad the locked outputs by the IsStandard lock dust value
|
||||
CTxOut dummyTxOut(Params().GetConsensus().pegged_asset, 0, relock_spk);
|
||||
CAmount lockDust(dummyTxOut.GetDustThreshold(withdrawLockTxFee));
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
std::vector<std::pair<COutPoint, CAmount> > lockedUTXO;
|
||||
if (!GetLockedOutputs(genesisBlockHash, value+lockDust, lockedUTXO))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Failed to find inputs with sufficient value - are you sure bitcoinTx is valid?");
|
||||
|
||||
while (lockedUTXO.size() != 1) {
|
||||
CMutableTransaction mtxn;
|
||||
mtxn.vin.push_back(CTxIn(lockedUTXO[0].first.hash, lockedUTXO[0].first.n, CScript(), ~(uint32_t)0));
|
||||
mtxn.vin.push_back(CTxIn(lockedUTXO[1].first.hash, lockedUTXO[1].first.n, CScript(), ~(uint32_t)0));
|
||||
CAmount out_value = lockedUTXO[0].second + lockedUTXO[1].second;
|
||||
mtxn.vout.push_back(CTxOut(Params().GetConsensus().pegged_asset, out_value, relock_spk));
|
||||
|
||||
CValidationState state;
|
||||
bool fMissingInputs;
|
||||
if (!AcceptToMemoryPool(mempool, state, MakeTransactionRef(mtxn), false, &fMissingInputs, NULL, false, true))
|
||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("Failed to merge locked outputs, please try again later (%i: %s)", state.GetRejectCode(), state.GetRejectReason()));
|
||||
|
||||
CInv inv(MSG_TX, mtxn.GetHash());
|
||||
g_connman->ForEachNode([&inv](CNode* pnode)
|
||||
{
|
||||
pnode->PushInventory(inv);
|
||||
});
|
||||
|
||||
lockedUTXO.erase(lockedUTXO.begin(), lockedUTXO.begin() + 2);
|
||||
lockedUTXO.push_back(std::make_pair(COutPoint(mtxn.GetHash(), 0), out_value));
|
||||
}
|
||||
|
||||
assert(lockedUTXO.size() == 1 && lockedUTXO[0].second >= value+lockDust);
|
||||
|
||||
uint256 utxo_txid(lockedUTXO[0].first.hash);
|
||||
uint32_t utxo_vout = lockedUTXO[0].first.n;
|
||||
CAmount utxo_value = lockedUTXO[0].second;
|
||||
|
||||
|
||||
CScript scriptSig;
|
||||
scriptSig << std::vector<unsigned char>(fullcontract, fullcontract + 40);
|
||||
scriptSig.PushWithdraw(txOutProofData);
|
||||
scriptSig.PushWithdraw(txData);
|
||||
scriptSig << nOut;
|
||||
|
||||
//Build the transaction
|
||||
CMutableTransaction mtxn;
|
||||
CTxIn txin(utxo_txid, utxo_vout, scriptSig, ~(uint32_t)0);
|
||||
CTxOut txout(Params().GetConsensus().pegged_asset, value, GetScriptForDestination(sidechainAddress.Get()));
|
||||
CTxOut txrelock(Params().GetConsensus().pegged_asset, utxo_value - value, relock_spk);
|
||||
mtxn.vin.push_back(txin);
|
||||
mtxn.vout.push_back(txout);
|
||||
mtxn.vout.push_back(txrelock);
|
||||
|
||||
//No signing needed, just send
|
||||
CTransaction finalTxn(mtxn);
|
||||
|
||||
CValidationState state;
|
||||
bool fMissingInputs;
|
||||
if (!AcceptToMemoryPool(mempool, state, MakeTransactionRef(finalTxn), false, &fMissingInputs, NULL, false, true))
|
||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("Failed to merge locked outputs, please try again later (%i: %s)", state.GetRejectCode(), state.GetRejectReason()));
|
||||
|
||||
CInv inv(MSG_TX, finalTxn.GetHash());
|
||||
g_connman->ForEachNode([&inv](CNode* pnode)
|
||||
{
|
||||
pnode->PushInventory(inv);
|
||||
});
|
||||
|
||||
AuditLogPrintf("%s : claimpegin %s\n", getUser(), finalTxn.ToString());
|
||||
|
||||
return finalTxn.GetHash().GetHex();
|
||||
}
|
||||
|
||||
UniValue issueasset(const JSONRPCRequest& request)
|
||||
{
|
||||
if (!EnsureWalletIsAvailable(request.fHelp))
|
||||
|
|
@ -4109,14 +3725,12 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "dumpissuanceblindingkey", &dumpissuanceblindingkey, true, {"txid", "vin"} },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
|
||||
{ "wallet", "claimpegin", &claimpegin, false, {} },
|
||||
{ "wallet", "getaccountaddress", &getaccountaddress, true, {"account"} },
|
||||
{ "wallet", "getaccount", &getaccount, true, {"address"} },
|
||||
{ "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, {"account"} },
|
||||
{ "wallet", "getbalance", &getbalance, false, {"account","minconf","include_watchonly"} },
|
||||
{ "wallet", "getnewaddress", &getnewaddress, true, {"account"} },
|
||||
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, true, {} },
|
||||
{ "wallet", "getpeginaddress", &getpeginaddress, false, {} },
|
||||
{ "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, {"account","minconf"} },
|
||||
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, {"address","minconf"} },
|
||||
{ "wallet", "gettransaction", &gettransaction, false, {"txid","include_watchonly"} },
|
||||
|
|
@ -4147,7 +3761,6 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "setaccount", &setaccount, true, {"address","account"} },
|
||||
{ "wallet", "reissueasset", &reissueasset, true, {"asset", "assetamount"} },
|
||||
{ "wallet", "signblock", &signblock, true, {} },
|
||||
{ "wallet", "sendtomainchain", &sendtomainchain, false, {} },
|
||||
{ "wallet", "destroyamount", &destroyamount, false, {"asset", "amount", "comment"} },
|
||||
{ "wallet", "settxfee", &settxfee, true, {"amount"} },
|
||||
{ "wallet", "signmessage", &signmessage, true, {"address","message"} },
|
||||
|
|
|
|||
|
|
@ -1492,10 +1492,8 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
|
|||
|
||||
if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
|
||||
{
|
||||
//Don't alarm user over blank address for withdrawLocks
|
||||
if (!txout.scriptPubKey.IsWithdrawLock())
|
||||
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
|
||||
this->GetHash().ToString());
|
||||
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
|
||||
this->GetHash().ToString());
|
||||
address = CNoDestination();
|
||||
}
|
||||
|
||||
|
|
@ -3317,8 +3315,8 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
|||
if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
|
||||
// Lastly, ensure this tx will pass the mempool's chain limits
|
||||
LockPoints lp;
|
||||
std::set<std::pair<uint256, COutPoint> > setWithdrawsSpent;
|
||||
CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp, setWithdrawsSpent);
|
||||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp, setPeginsSpent);
|
||||
CTxMemPool::setEntries setAncestors;
|
||||
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
|
||||
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue