Commit 71b45cd3 authored by Tom Zander's avatar Tom Zander

Merge branch 'dev/HFNov2018'

parents 1ea759cf 1ce0fb90
Pipeline #36786605 passed with stages
in 23 minutes and 13 seconds
......@@ -175,6 +175,7 @@ public:
consensus.hf201708BlockId = uint256S("0x000000000000000000651ef99cb9fcbe0dadde1d424bd9f15ff20136191a5eec");
consensus.hf201711Height = 504032;
consensus.hf201805Height = 530356;
consensus.hf201811Height = 556767;
checkpointData = CCheckpointData {
boost::assign::map_list_of
......@@ -284,6 +285,7 @@ public:
consensus.hf201708BlockId = uint256S("0x00000000000e38fef93ed9582a7df43815d5c2ba9fd37ef70c9a0ea4a285b8f5");
consensus.hf201711Height = 1;
consensus.hf201805Height = 1;
consensus.hf201811Height = 1;
checkpointData = CCheckpointData {
boost::assign::map_list_of
......@@ -361,6 +363,7 @@ public:
consensus.hf201708BlockId = consensus.hashGenesisBlock;
consensus.hf201711Height = 1;
consensus.hf201805Height = 1;
consensus.hf201811Height = 9999999; // avoid doing stupid stuff like 100 bytes min tx size
checkpointData = CCheckpointData {
boost::assign::map_list_of
......
......@@ -83,6 +83,7 @@ struct Params {
int hf201711Height; // daa3 got enabled here
int64_t daa3ActivationTime; // difficulty adjustment algo 3, the one that removed the broken EDA.
int hf201805Height;
int hf201811Height;
};
} // namespace Consensus
......
......@@ -329,6 +329,11 @@ CBlockTemplate* Mining::CreateNewBlock(Validation::Engine &validationEngine) con
// Compute final coinbase transaction.
txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, Params().GetConsensus());
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0 << m_coinbaseComment;
// Make sure the coinbase is big enough. (since 20181115 HF we require a min 100bytes tx size)
const uint32_t coinbaseSize = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
if (coinbaseSize < 100)
txNew.vin[0].scriptSig << std::vector<uint8_t>(100 - coinbaseSize - 1);
pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;
......
This diff is collapsed.
......@@ -105,10 +105,20 @@ enum
// Do we accept signature using SIGHASH_FORKID
//
SCRIPT_ENABLE_SIGHASH_FORKID = (1U << 16),
// If OP_CHECKDATASIG* are allowed.
SCRIPT_ENABLE_CHECKDATASIG = (1U << 17),
};
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
/**
* Check that the signature provided on some data is properly encoded.
* Signatures passed to OP_CHECKDATASIG and its verify variant must be checked
* using this function.
*/
bool CheckDataSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags, ScriptError *serror);
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, CAmount amount, int nHashType, uint32_t flags = SCRIPT_ENABLE_SIGHASH_FORKID);
class BaseSignatureChecker
......
......@@ -3,6 +3,7 @@
* Copyright (C) 2009-2010 Satoshi Nakamoto
* Copyright (C) 2009-2015 The Bitcoin Core developers
* Copyright (C) 2018 Jason B. Cox <contact@jasonbcox.com>
* Copyright (C) 2018 Tom Zander <tomz@freedommail.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -142,7 +143,7 @@ const char* GetOpName(opcodetype opcode)
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
// expanson
// soft-forkable expansion
case OP_NOP1 : return "OP_NOP1";
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_NOP3 : return "OP_NOP3";
......@@ -154,6 +155,10 @@ const char* GetOpName(opcodetype opcode)
case OP_NOP9 : return "OP_NOP9";
case OP_NOP10 : return "OP_NOP10";
// new opcodes hard-forked in.
case OP_CHECKDATASIG: return "OP_CHECKDATASIG";
case OP_CHECKDATASIGVERIFY: return "OP_CHECKDATASIGVERIFY";
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
// Note:
......@@ -171,15 +176,16 @@ unsigned int CScript::GetSigOpCount(bool fAccurate) const
unsigned int n = 0;
const_iterator pc = begin();
opcodetype lastOpcode = OP_INVALIDOPCODE;
while (pc < end())
{
while (pc < end()) {
opcodetype opcode;
if (!GetOp(pc, opcode))
break;
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY
|| opcode == OP_CHECKDATASIG || opcode == OP_CHECKDATASIGVERIFY) {
n++;
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
{
}
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY) {
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
n += DecodeOP_N(lastOpcode);
else
......
......@@ -186,6 +186,11 @@ enum opcodetype
OP_NOP9 = 0xb8,
OP_NOP10 = 0xb9,
// Hard fork expansion starts here.
// New since 2018-11
OP_CHECKDATASIG = 0xba,
OP_CHECKDATASIGVERIFY = 0xbb,
// template matching params
OP_SMALLINTEGER = 0xfa,
......
......@@ -2,6 +2,8 @@
* This file is part of the Flowee project
* Copyright (C) 2009-2010 Satoshi Nakamoto
* Copyright (C) 2009-2014 The Bitcoin Core developers
* Copyright (C) 2018 Awemany <awemany@protonmail.com>
* Copyright (C) 2018 Amaury Séchet <deadalnix@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -35,6 +37,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Script failed an OP_CHECKMULTISIGVERIFY operation";
case SCRIPT_ERR_CHECKSIGVERIFY:
return "Script failed an OP_CHECKSIGVERIFY operation";
case SCRIPT_ERR_CHECKDATASIGVERIFY:
return "Script failed an OP_CHECKDATASIGVERIFY operation";
case SCRIPT_ERR_NUMEQUALVERIFY:
return "Script failed an OP_NUMEQUALVERIFY operation";
case SCRIPT_ERR_SCRIPT_SIZE:
......
......@@ -46,6 +46,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_EQUALVERIFY,
SCRIPT_ERR_CHECKMULTISIGVERIFY,
SCRIPT_ERR_CHECKSIGVERIFY,
SCRIPT_ERR_CHECKDATASIGVERIFY,
SCRIPT_ERR_NUMEQUALVERIFY,
/* Logical/Format/Canonical errors */
......
This diff is collapsed.
......@@ -48,6 +48,7 @@ struct ValidationFlags {
bool nLocktimeVerifySequence;
bool hf201708Active;
bool hf201805Active;
bool hf201811Active;
uint32_t scriptValidationFlags() const;
......@@ -68,6 +69,7 @@ void validateTransactionInputs(CTransaction &tx, const std::vector<UnspentOutput
}
struct Output {
Output(int index, int offsetInBlock) : index(index), offsetInBlock(offsetInBlock) {}
uint256 txid;
int index = -1;
int offsetInBlock = 0;
......@@ -135,9 +137,6 @@ public:
/// When the previous block's transactions are added to the UTXO, we start our validation.
void updateUtxoAndStartValidation();
// this throws on double-spend detection (in-block)
void findOrderedTransactions();
/**
* @brief calculateTxCheckChunks returns the amount of 'chunks' we split the transaction pool into for parallel validation.
* @param[out] chunks the chunk-count.
......@@ -150,7 +149,6 @@ public:
}
FastBlock m_block;
std::set<int> m_orderedTransactions; // filled with the transactions indexes that have to be processed 'in-order' because they depend on each other.
CDiskBlockPos m_blockPos;
CBlockIndex *m_blockIndex;
......
......@@ -199,6 +199,9 @@ void TxValidationState::checkTransaction()
};
RAII raii(&m_promise);
if (flags.hf201811Active && m_tx.size() < 100)
throw Exception("bad-txns-undersize", 2);
const uint256 txid = m_tx.createHash();
DEBUGTX << "checkTransaction peer:" << m_originatingNodeId << txid;
auto tx = m_tx.createOldTransaction();
......
......@@ -62,6 +62,21 @@ public:
memset(data, 0, sizeof(data));
}
inline int Compare(const base_blob &other) const {
for (size_t i = 0; i < sizeof(data); i++) {
uint8_t a = data[sizeof(data) - 1 - i];
uint8_t b = other.data[sizeof(data) - 1 - i];
if (a > b) {
return 1;
}
if (a < b) {
return -1;
}
}
return 0;
}
friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; }
friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; }
friend inline bool operator<(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) < 0; }
......
......@@ -218,6 +218,11 @@ void UnspentOutputDatabase::setSmallLimits()
UODBPrivate::limits.FileFull = 30000000;
}
void UnspentOutputDatabase::insertAll(const UnspentOutputDatabase::BlockData &data)
{
d->dataFiles.last()->insertAll(d, data);
}
void UnspentOutputDatabase::insert(const uint256 &txid, int outIndex, int blockHeight, int offsetInBlock)
{
d->dataFiles.last()->insert(d, txid, outIndex, blockHeight, offsetInBlock);
......@@ -640,6 +645,14 @@ void DataFile::insert(const UODBPrivate *priv, const uint256 &txid, int outIndex
addChange(priv);
}
void DataFile::insertAll(const UODBPrivate *priv, const UnspentOutputDatabase::BlockData &data)
{
std::lock_guard<std::recursive_mutex> lock(m_lock);
for (auto d : data.outputs) {
insert(priv, d.txid, d.index, data.blockHeight, d.offsetInBlock);
}
}
UnspentOutput DataFile::find(const uint256 &txid, int index) const
{
LockGuard lock(this);
......
......@@ -105,6 +105,18 @@ public:
/// Change limits to be smaller, for instance for regtest setups
static void setSmallLimits();
struct BlockData {
struct TxOutput {
TxOutput(int i) : index(i) {}
uint256 txid;
int index = -1;
int offsetInBlock = 0;
};
int blockHeight = -1;
std::vector<TxOutput> outputs;
};
void insertAll(const BlockData &data);
/**
* @brief insert a new spendable output.
* @param txid the (prev) transaction id.
......
......@@ -140,6 +140,7 @@ public:
DataFile(const boost::filesystem::path &filename);
void insert(const UODBPrivate *priv, const uint256 &txid, int outIndex, int blockHeight, int offsetInBlock);
void insertAll(const UODBPrivate *priv, const UnspentOutputDatabase::BlockData &data);
UnspentOutput find(const uint256 &txid, int index) const;
SpentOutput remove(const UODBPrivate *priv, const uint256 &txid, int index, uint32_t leafHint = 0);
......
......@@ -51,6 +51,10 @@ FastBlock MockBlockValidation::createBlock(CBlockIndex *parent, const CScript& s
coinbase.vin[0].scriptSig = CScript() << (parent->nHeight + 1) << OP_0;
coinbase.vout[0].nValue = 50 * COIN;
coinbase.vout[0].scriptPubKey = scriptPubKey;
// Make sure the coinbase is big enough. (since 20181115 HF we require a min 100bytes tx size)
const uint32_t coinbaseSize = ::GetSerializeSize(coinbase, SER_NETWORK, PROTOCOL_VERSION);
if (coinbaseSize < 100)
coinbase.vin[0].scriptSig << std::vector<uint8_t>(100 - coinbaseSize - 1);
CBlock block;
block.vtx.push_back(coinbase);
......
......@@ -28,7 +28,7 @@ using boost::unit_test::test_suite;
test_suite* init_unit_test_suite(int, char* [])
{
SelectParams("main");
setupBacktraceCatcher();
// setupBacktraceCatcher();
return BOOST_TEST_SUITE("Flowee generic test suite");
}
......@@ -54,6 +54,7 @@ set (TEST_SOURCES
blockvalidation_tests.cpp
bloom_tests.cpp
bswap_tests.cpp
checkdatasig_tests.cpp
Checkpoints_tests.cpp
compress_tests.cpp
crypto_tests.cpp
......
......@@ -22,6 +22,7 @@
#include <validation/BlockValidation_p.h>
#include <server/BlocksDB.h>
#include <server/script/interpreter.h>
#include <server/script/standard.h>
#include <primitives/transaction.h>
#include <chainparams.h>
#include <key.h>
......@@ -200,7 +201,6 @@ BOOST_AUTO_TEST_CASE(detectOrder2)
BOOST_AUTO_TEST_CASE(duplicateInput)
{
CKey coinbaseKey;
coinbaseKey.MakeNewKey(true);
// create a chain of 101 blocks.
std::vector<FastBlock> blocks = bv.appendChain(101, coinbaseKey);
assert(blocks.size() == 101);
......@@ -238,4 +238,94 @@ BOOST_AUTO_TEST_CASE(duplicateInput)
BOOST_CHECK_EQUAL(future.error(), std::string("bad-txns-inputs-duplicate"));
}
// this only works if the input is a p2pkh script!
CTransaction splitCoins(const Tx &inTx, int inIndex, const CKey &from, const CKey &to, int outputCount)
{
assert(outputCount > 0);
assert(inIndex >= 0);
logInfo() << inTx.createHash();
Tx::Output prevOut = inTx.output(inIndex);
assert(prevOut.outputValue > 0);
const uint64_t outAmount = prevOut.outputValue / outputCount;
assert(outAmount > 5);
CMutableTransaction newTx;
CTxIn input;
input.prevout.n = inIndex;
input.prevout.hash = inTx.createHash();
newTx.vin.push_back(input);
const CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(to.GetPubKey().GetID())
<< OP_EQUALVERIFY << OP_CHECKSIG;
newTx.vout.resize(outputCount);
for (int i = 0; i < outputCount; ++i) {
newTx.vout[i].nValue = outAmount;
newTx.vout[i].scriptPubKey = scriptPubKey;
}
// Sign
const int nHashType = SIGHASH_ALL | SIGHASH_FORKID;
const uint256 sigHash = SignatureHash(prevOut.outputScript, newTx, inIndex, prevOut.outputValue, nHashType, SCRIPT_ENABLE_SIGHASH_FORKID);
std::vector<unsigned char> vchSig;
bool ok = from.Sign(sigHash, vchSig);
assert(ok);
vchSig.push_back((unsigned char)nHashType);
newTx.vin[0].scriptSig << vchSig;
newTx.vin[0].scriptSig << ToByteVector(from.GetPubKey());
return newTx;
}
bool sortTxByTxId(const CTransaction &tx1, const CTransaction &tx2)
{
return tx1.GetHash().Compare(tx2.GetHash()) <= 0;
}
BOOST_AUTO_TEST_CASE(CTOR)
{
auto priv = bv.priv().lock();
priv->tipFlags.hf201811Active = true;
CKey myKey;
// create a chain of 101 blocks.
std::vector<FastBlock> blocks = bv.appendChain(110, myKey, MockBlockValidation::FullOutScript);
assert(blocks.size() == 110);
FastBlock block1 = blocks.at(1);
block1.findTransactions();
const int OUTPUT_COUNT = 100;
std::vector<CTransaction> txs;
CTransaction root = splitCoins(block1.transactions().at(0),
0, myKey, myKey, OUTPUT_COUNT);
txs.push_back(root);
for (int i = 1; i < 5; ++i) {
txs.push_back(splitCoins(Tx::fromOldTransaction(root), i, myKey, myKey, 10));
}
for (size_t i = 0; i < txs.size(); ++i) {
// logDebug() << "tx" << i << txs.at(i).GetHash() << "in" << txs.at(i).vin.size()
// << "out" << txs.at(i).vout.size();
}
CKey coinbaseKey;
coinbaseKey.MakeNewKey(true);
CScript scriptPubKey;
scriptPubKey << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
FastBlock unsortedBlock = bv.createBlock(bv.blockchain()->Tip(), scriptPubKey, txs);
auto future = bv.addBlock(unsortedBlock, Validation::SaveGoodToDisk).start();
future.waitUntilFinished();
BOOST_CHECK_EQUAL("tx-ordering-not-CTOR", future.error());
// sort the transactions and then mine it again.
std::sort(txs.begin(), txs.end(), &sortTxByTxId);
FastBlock sortedBlock = bv.createBlock(bv.blockchain()->Tip(), scriptPubKey, txs);
future = bv.addBlock(sortedBlock, Validation::SaveGoodToDisk).start();
future.waitUntilFinished();
// I intended the actual validation to go fully Ok, but I get some signature failures.
BOOST_CHECK("tx-ordering-not-CTOR" != future.error());
BOOST_CHECK("missing-inputs" != future.error());
}
BOOST_AUTO_TEST_SUITE_END()
This diff is collapsed.
......@@ -175,6 +175,10 @@ FastBlock MockBlockValidation::createBlock(CBlockIndex *parent, const CScript& s
coinbase.vin[0].scriptSig = CScript() << (parent->nHeight + 1) << OP_0;
coinbase.vout[0].nValue = 50 * COIN;
coinbase.vout[0].scriptPubKey = scriptPubKey;
// Make sure the coinbase is big enough. (since 20181115 HF we require a min 100bytes tx size)
const uint32_t coinbaseSize = ::GetSerializeSize(coinbase, SER_NETWORK, PROTOCOL_VERSION);
if (coinbaseSize < 100)
coinbase.vin[0].scriptSig << std::vector<uint8_t>(100 - coinbaseSize - 1);
CBlock block;
block.vtx.push_back(coinbase);
......@@ -219,8 +223,12 @@ std::vector<FastBlock> MockBlockValidation::appendChain(int blocks, CKey &coinba
answer.reserve(blocks);
coinbaseKey.MakeNewKey();
CScript scriptPubKey;
if (out == StandardOutScript)
scriptPubKey << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
if (out == StandardOutScript) {
scriptPubKey << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
} else if (out == FullOutScript) {
scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(coinbaseKey.GetPubKey().GetID())
<< OP_EQUALVERIFY << OP_CHECKSIG;
}
waitValidationFinished();
const bool allowFullChecks = Params().NetworkIDString() == "regtest";
for (int i = 0; i < blocks; i++)
......
......@@ -65,7 +65,8 @@ public:
enum OutputType {
EmptyOutScript,
StandardOutScript
StandardOutScript,
FullOutScript // full p2pkh output script
};
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment