Files

1141 lines
56 KiB
C++
Raw Permalink Normal View History

2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2011-2015 The Bitcoin Core developers
2021-01-20 19:21:53 +01:00
* Copyright (C) 2016-2021 Tom Zander <tom@flowee.org>
2018-04-16 11:59:19 +02:00
* Copyright (C) 2018 Jason B. Cox <contact@jasonbcox.com>
2017-11-09 19:34:51 +01:00
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2014-03-18 10:11:00 +01:00
2018-12-28 12:10:28 +01:00
#include "script_tests.h"
#include "transaction_tests.h"
2013-04-13 00:13:08 -05:00
#include "data/script_invalid.json.h"
#include "data/script_valid.json.h"
2017-07-24 22:40:28 +02:00
#include "rpcserver.h"
2016-09-15 22:48:59 +02:00
#include "transaction_utils.h"
2013-04-13 00:13:08 -05:00
2021-01-20 18:22:34 +01:00
#include <common/MutableTransactionSignatureChecker.h>
#include <core_io.h>
#include <keystore.h>
2026-05-08 22:11:32 +02:00
#include <primitives/ScriptBigNum_p.h>
2026-05-07 21:10:10 +02:00
#include <primitives/ScriptDefines.h> // for MAX_SCRIPT_ELEMENT_SIZE
#include <script/standard.h>
#include <utilstrencodings.h>
2013-04-13 00:13:08 -05:00
2026-05-08 22:11:32 +02:00
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
2014-10-07 02:22:47 +02:00
// Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS
2012-11-13 23:03:25 +01:00
static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
2011-07-31 20:01:31 +02:00
std::string FormatScriptFlags(unsigned int flags);
2018-12-28 12:10:28 +01:00
UniValue read_json(const std::string& jsondata)
2012-04-17 17:57:06 -04:00
{
UniValue v;
2012-04-17 17:57:06 -04:00
if (!v.read(jsondata) || !v.isArray())
{
2018-12-28 12:10:28 +01:00
Q_ASSERT(false);
return UniValue(UniValue::VARR);
}
2012-04-17 17:57:06 -04:00
return v.get_array();
}
2021-01-20 19:21:53 +01:00
CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int64_t amount = 0)
{
CMutableTransaction txCredit;
txCredit.nVersion = 1;
txCredit.nLockTime = 0;
txCredit.vin.resize(1);
txCredit.vout.resize(1);
txCredit.vin[0].prevout.SetNull();
txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
2015-12-07 15:44:16 -05:00
txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
txCredit.vout[0].scriptPubKey = scriptPubKey;
2017-07-24 22:40:28 +02:00
txCredit.vout[0].nValue = amount;
return txCredit;
}
2014-09-28 06:33:33 +02:00
CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
{
CMutableTransaction txSpend;
txSpend.nVersion = 1;
txSpend.nLockTime = 0;
txSpend.vin.resize(1);
txSpend.vout.resize(1);
txSpend.vin[0].prevout.hash = txCredit.GetHash();
txSpend.vin[0].prevout.n = 0;
txSpend.vin[0].scriptSig = scriptSig;
2015-12-07 15:44:16 -05:00
txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
txSpend.vout[0].scriptPubKey = CScript();
2017-07-24 22:40:28 +02:00
txSpend.vout[0].nValue = txCredit.vout[0].nValue;
return txSpend;
}
2021-01-20 19:21:53 +01:00
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const QString &message, int64_t nValue)
{
2017-07-24 22:40:28 +02:00
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey, nValue));
2014-10-14 18:23:46 -04:00
CMutableTransaction tx2 = tx;
2020-04-11 18:35:43 +02:00
Script::State state(flags);
2026-05-04 23:22:01 +02:00
const bool result = Script::verify(scriptSig, scriptPubKey, MutableTransactionSignatureChecker(&tx, 0, nValue), state);
2020-04-11 18:35:43 +02:00
if ((state.error == SCRIPT_ERR_OK) != expect)
qWarning() << QString(state.errorString()) + ": " + message;
2026-05-04 23:22:01 +02:00
QCOMPARE(result, expect);
2020-04-11 18:35:43 +02:00
QCOMPARE(state.error == SCRIPT_ERR_OK, expect);
}
2014-11-05 10:53:59 -08:00
void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
// Parse the signature.
std::vector<unsigned char> r, s;
r = std::vector<unsigned char>(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]);
s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]);
// Really ugly to implement mod-n negation here, but it would be feature creep to expose such functionality from libsecp256k1.
static const unsigned char order[33] = {
0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
};
while (s.size() < 33) {
s.insert(s.begin(), 0x00);
}
int carry = 0;
for (int p = 32; p >= 1; p--) {
int n = (int)order[p] - s[p] - carry;
s[p] = (n + 256) & 0xFF;
carry = (n < 0);
}
2018-12-28 12:10:28 +01:00
Q_ASSERT(carry == 0);
2014-11-05 10:53:59 -08:00
if (s.size() > 1 && s[0] == 0 && s[1] < 0x80) {
s.erase(s.begin());
}
// Reconstruct the signature.
vchSig.clear();
vchSig.push_back(0x30);
vchSig.push_back(4 + r.size() + s.size());
vchSig.push_back(0x02);
vchSig.push_back(r.size());
vchSig.insert(vchSig.end(), r.begin(), r.end());
vchSig.push_back(0x02);
vchSig.push_back(s.size());
vchSig.insert(vchSig.end(), s.begin(), s.end());
}
namespace
{
const unsigned char vchKey0[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
const unsigned char vchKey1[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0};
const unsigned char vchKey2[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0};
struct KeyData
{
2018-12-28 12:10:28 +01:00
KeyData();
2022-07-06 22:12:33 +02:00
PrivateKey key0, key0C, key1, key1C, key2, key2C;
2022-07-06 21:56:34 +02:00
PublicKey pubkey0, pubkey0C, pubkey0H;
PublicKey pubkey1, pubkey1C;
PublicKey pubkey2, pubkey2C;
};
2018-12-28 12:10:28 +01:00
KeyData::KeyData()
{
2022-05-11 13:12:33 +02:00
key0.set(vchKey0, vchKey0 + 32, false);
key0C.set(vchKey0, vchKey0 + 32, true);
2022-05-11 13:46:15 +02:00
pubkey0 = key0.getPubKey();
pubkey0H = key0.getPubKey();
pubkey0C = key0C.getPubKey();
2018-12-28 12:10:28 +01:00
*const_cast<unsigned char*>(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1);
2022-05-11 13:12:33 +02:00
key1.set(vchKey1, vchKey1 + 32, false);
key1C.set(vchKey1, vchKey1 + 32, true);
2022-05-11 13:46:15 +02:00
pubkey1 = key1.getPubKey();
pubkey1C = key1C.getPubKey();
2022-05-11 13:12:33 +02:00
key2.set(vchKey2, vchKey2 + 32, false);
key2C.set(vchKey2, vchKey2 + 32, true);
2022-05-11 13:46:15 +02:00
pubkey2 = key2.getPubKey();
pubkey2C = key2C.getPubKey();
}
2018-12-28 12:10:28 +01:00
}
void TestBuilder::DoPush()
{
if (havePush) {
spendTx.vin[0].scriptSig << push;
havePush = false;
}
}
void TestBuilder::DoPush(const std::vector<unsigned char>& data)
{
DoPush();
push = data;
havePush = true;
}
2021-01-20 19:21:53 +01:00
TestBuilder::TestBuilder(const CScript& redeemScript, const QString &comment, int flags_, bool P2SH, int64_t nValue_)
2018-12-28 12:10:28 +01:00
: scriptPubKey(redeemScript), havePush(false), comment(comment), flags(flags_), nValue(nValue_)
{
if (P2SH) {
creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL, nValue);
} else {
creditTx = BuildCreditingTransaction(redeemScript, nValue);
}
spendTx = BuildSpendingTransaction(CScript(), creditTx);
}
TestBuilder& TestBuilder::Add(const CScript& script)
{
DoPush();
spendTx.vin[0].scriptSig += script;
return *this;
}
TestBuilder& TestBuilder::Num(int num)
{
DoPush();
spendTx.vin[0].scriptSig << num;
return *this;
}
TestBuilder& TestBuilder::Push(const std::string& hex)
{
DoPush(ParseHex(hex));
return *this;
}
2022-07-06 22:12:33 +02:00
TestBuilder& TestBuilder::PushSig(const PrivateKey& key, int nHashType, unsigned int lenR, unsigned int lenS, int64_t amount)
2018-12-28 12:10:28 +01:00
{
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, amount, nHashType);
std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0;
do {
2021-04-19 15:45:02 +02:00
key.signECDSA(hash, vchSig, iter++);
2018-12-28 12:10:28 +01:00
if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) {
NegateSignatureS(vchSig);
}
r = std::vector<unsigned char>(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]);
s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]);
} while (lenR != r.size() || lenS != s.size());
vchSig.push_back(static_cast<unsigned char>(nHashType));
DoPush(vchSig);
return *this;
}
2022-07-06 21:56:34 +02:00
TestBuilder& TestBuilder::Push(const PublicKey& pubkey)
2018-12-28 12:10:28 +01:00
{
DoPush(std::vector<unsigned char>(pubkey.begin(), pubkey.end()));
return *this;
}
TestBuilder& TestBuilder::PushRedeem()
{
DoPush(std::vector<unsigned char>(scriptPubKey.begin(), scriptPubKey.end()));
return *this;
}
TestBuilder& TestBuilder::EditPush(unsigned int pos, const std::string& hexin, const std::string& hexout)
{
Q_ASSERT(havePush);
std::vector<unsigned char> datain = ParseHex(hexin);
std::vector<unsigned char> dataout = ParseHex(hexout);
Q_ASSERT(pos + datain.size() <= push.size());
Q_ASSERT(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain);
push.erase(push.begin() + pos, push.begin() + pos + datain.size());
push.insert(push.begin() + pos, dataout.begin(), dataout.end());
return *this;
}
TestBuilder& TestBuilder::DamagePush(unsigned int pos)
{
Q_ASSERT(havePush);
Q_ASSERT(pos < push.size());
push[pos] ^= 1;
return *this;
}
TestBuilder& TestBuilder::Test(bool expect)
{
TestBuilder copy = *this; // Make a copy so we can rollback the push.
DoPush();
DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment, nValue);
*this = copy;
return *this;
}
UniValue TestBuilder::GetJSON()
{
DoPush();
UniValue array(UniValue::VARR);
if (nValue != 0) {
UniValue amount(UniValue::VARR);
amount.push_back(ValueFromAmount(nValue));
array.push_back(amount);
}
array.push_back(TxUtils::FormatScript(spendTx.vin[0].scriptSig));
array.push_back(TxUtils::FormatScript(creditTx.vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
array.push_back(comment.toStdString());
return array;
}
QString TestBuilder::GetComment() const
{
return comment;
}
const CScript& TestBuilder::GetScriptPubKey()
{
return creditTx.vout[0].scriptPubKey;
}
void TestScript::script_build()
{
2014-11-05 09:43:44 -08:00
const KeyData keys;
std::vector<TestBuilder> good;
std::vector<TestBuilder> bad;
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK", 0
).PushSig(keys.key0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK, bad sig", 0
).PushSig(keys.key0).DamagePush(10));
2021-04-19 11:58:00 +02:00
good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.getKeyId()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2PKH", 0
).PushSig(keys.key1).Push(keys.pubkey1C));
2021-04-19 11:58:00 +02:00
bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.getKeyId()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2PKH, bad pubkey", 0
).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay marked with normal hashtype", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem().DamagePush(10));
2021-04-19 11:58:00 +02:00
good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.getKeyId()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true
).PushSig(keys.key0).DamagePush(10).PushRedeem());
2021-04-19 11:58:00 +02:00
bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.getKeyId()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).DamagePush(10).PushRedeem());
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3", 0
).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3, 2 sigs", 0
).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true
).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem());
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true
).Num(0).PushSig(keys.key1).Num(0).PushRedeem());
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much S padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much S padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too little R padding but no DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too little R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with bad sig with too much R padding but no DERSIG", 0
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with too much R padding but no DERSIG", 0
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
2015-01-19 18:19:37 -05:00
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 1, without DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 2, without DERSIG", 0
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 3, without DERSIG", 0
).Num(0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 4, without DERSIG", 0
).Num(0));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 5, without DERSIG", 0
).Num(1));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(1));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 6, without DERSIG", 0
).Num(1));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(1));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 7, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 8, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 9, without DERSIG", 0
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 10, without DERSIG", 0
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 11, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 12, without DERSIG", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG
).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
2015-02-10 12:11:59 -05:00
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with multi-byte hashtype, without DERSIG", 0
).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG
).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101"));
2015-01-19 18:19:37 -05:00
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S", SCRIPT_VERIFY_LOW_S
).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).Num(0).PushSig(keys.key1, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).Num(0).PushSig(keys.key1, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key1, 5));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key1, 5).DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3 with nonzero dummy but no NULLDUMMY", 0
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT,
"3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
bad.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT,
"3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0
).PushSig(keys.key2).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY
).PushSig(keys.key2).PushRedeem());
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).PushSig(keys.key1));
2014-10-12 18:39:47 -07:00
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH
).Num(11).PushSig(keys.key0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH
).Num(11).PushSig(keys.key0));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true
).Num(11).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
).Num(11).PushSig(keys.key0).PushRedeem());
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem());
2021-01-20 19:21:53 +01:00
static const int64_t TEST_AMOUNT = 12345000000000;
2017-07-24 22:40:28 +02:00
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK FORKID", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT)
.PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID AMOUNT", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT)
.PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT + 1));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID FORKID", SCRIPT_VERIFY_STRICTENC, false, TEST_AMOUNT)
.PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID, 32, 32, TEST_AMOUNT));
std::set<std::string> tests_good;
std::set<std::string> tests_bad;
{
2015-05-13 21:29:19 +02:00
UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
2015-05-10 13:35:44 +02:00
for (unsigned int idx = 0; idx < json_good.size(); idx++) {
const UniValue& tv = json_good[idx];
2015-05-10 13:35:44 +02:00
tests_good.insert(tv.get_array().write());
}
2015-05-10 13:35:44 +02:00
for (unsigned int idx = 0; idx < json_bad.size(); idx++) {
const UniValue& tv = json_bad[idx];
2015-05-10 13:35:44 +02:00
tests_bad.insert(tv.get_array().write());
}
}
std::string strGood;
std::string strBad;
for (TestBuilder& test : good) {
test.Test(true);
2015-05-10 13:35:44 +02:00
std::string str = test.GetJSON().write();
2014-10-07 02:22:47 +02:00
#ifndef UPDATE_JSON_TESTS
if (tests_good.count(str) == 0) {
2018-12-28 12:10:28 +01:00
qWarning() << "Missing auto script_valid test: " << test.GetComment();
QFAIL("Missing auto script_valid");
2014-10-07 02:22:47 +02:00
}
#endif
strGood += str + ",\n";
}
2018-12-28 12:10:28 +01:00
for (TestBuilder &test : bad) {
test.Test(false);
2015-05-10 13:35:44 +02:00
std::string str = test.GetJSON().write();
2014-10-07 02:22:47 +02:00
#ifndef UPDATE_JSON_TESTS
if (tests_bad.count(str) == 0) {
2018-12-28 12:10:28 +01:00
QFAIL("Missing auto script_invalid");
2014-10-07 02:22:47 +02:00
}
#endif
strBad += str + ",\n";
}
2014-10-07 02:22:47 +02:00
#ifdef UPDATE_JSON_TESTS
FILE* valid = fopen("script_valid.json.gen", "w");
fputs(strGood.c_str(), valid);
fclose(valid);
FILE* invalid = fopen("script_invalid.json.gen", "w");
fputs(strBad.c_str(), invalid);
fclose(invalid);
#endif
}
2018-12-28 12:10:28 +01:00
void TestScript::script_valid()
2012-04-17 17:57:06 -04:00
{
// Read tests from test/data/script_valid.json
// Format is an array of arrays
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
2012-04-17 17:57:06 -04:00
// ... where scriptSig and scriptPubKey are stringified
// scripts.
2015-05-13 21:29:19 +02:00
UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
2012-04-17 17:57:06 -04:00
for (unsigned int idx = 0; idx < tests.size(); idx++) {
2015-05-13 21:29:19 +02:00
UniValue test = tests[idx];
2018-12-28 12:10:28 +01:00
QString strTest = QString::fromStdString(test.write());
2021-01-20 19:21:53 +01:00
int64_t nValue = 0;
2017-07-24 22:40:28 +02:00
unsigned int pos = 0;
if (test.size() > 0 && test[pos].isArray()) {
nValue = AmountFromValue(test[pos][0]);
pos++;
}
if (test.size() < 3 + pos) // Allow size > 3; extra stuff ignored (useful for comments)
2012-04-17 17:57:06 -04:00
{
if (test.size() != 1) {
2018-12-28 12:10:28 +01:00
qWarning() << "bad test" << strTest;
QFAIL("Bad test");
}
2012-04-17 17:57:06 -04:00
continue;
}
std::string scriptSigString = test[pos++].get_str();
2012-04-17 17:57:06 -04:00
CScript scriptSig = ParseScript(scriptSigString);
std::string scriptPubKeyString = test[pos++].get_str();
2012-04-17 17:57:06 -04:00
CScript scriptPubKey = ParseScript(scriptPubKeyString);
2018-12-28 12:10:28 +01:00
unsigned int scriptflags = TransactionTests::parseScriptFlags(test[pos++].get_str());
2012-04-17 17:57:06 -04:00
2017-07-24 22:40:28 +02:00
DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest, nValue);
2012-04-17 17:57:06 -04:00
}
}
2018-12-28 12:10:28 +01:00
void TestScript::script_invalid()
2012-04-17 17:57:06 -04:00
{
// Scripts that should evaluate as invalid
2015-05-13 21:29:19 +02:00
UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
2012-04-17 17:57:06 -04:00
for (unsigned int idx = 0; idx < tests.size(); idx++) {
2015-05-13 21:29:19 +02:00
UniValue test = tests[idx];
2018-12-28 12:10:28 +01:00
QString strTest = QString::fromStdString(test.write());
2021-01-20 19:21:53 +01:00
int64_t nValue = 0;
2017-07-24 22:40:28 +02:00
unsigned int pos = 0;
if (test.size() > 0 && test[pos].isArray()) {
nValue = AmountFromValue(test[pos][0]);
pos++;
}
if (test.size() < 3 + pos) // Allow size > 2; extra stuff ignored (useful for comments)
2012-04-17 17:57:06 -04:00
{
if (test.size() != 1) {
2018-12-28 12:10:28 +01:00
qWarning() << "bad test" << strTest;
QFAIL("Bad test");
}
2012-04-17 17:57:06 -04:00
continue;
}
std::string scriptSigString = test[pos++].get_str();
2012-04-17 17:57:06 -04:00
CScript scriptSig = ParseScript(scriptSigString);
std::string scriptPubKeyString = test[pos++].get_str();
2012-04-17 17:57:06 -04:00
CScript scriptPubKey = ParseScript(scriptPubKeyString);
2018-12-28 12:10:28 +01:00
unsigned int scriptflags = TransactionTests::parseScriptFlags(test[pos++].get_str());
2012-04-17 17:57:06 -04:00
2017-07-24 22:40:28 +02:00
DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest, nValue);
2012-04-17 17:57:06 -04:00
}
}
2018-12-28 12:10:28 +01:00
void TestScript::script_PushData()
2011-07-31 20:01:31 +02:00
{
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
// the stack as the 1-75 opcodes do.
static const unsigned char direct[] = { 1, 0x5a };
static const unsigned char pushdata1[] = { OP_PUSHDATA1, 1, 0x5a };
static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };
static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
2020-04-11 18:35:43 +02:00
Script::State state(SCRIPT_VERIFY_P2SH);
std::vector<std::vector<unsigned char> > directStack;
2020-04-11 18:35:43 +02:00
QVERIFY(Script::eval(directStack, CScript(&direct[0], &direct[sizeof(direct)]), BaseSignatureChecker(), state));
QCOMPARE(state.errorString(), "No error");
2011-07-31 20:01:31 +02:00
2020-04-11 18:35:43 +02:00
std::vector<std::vector<unsigned char>> pushdata1Stack;
state = Script::State(SCRIPT_VERIFY_P2SH);
QVERIFY(Script::eval(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), BaseSignatureChecker(), state));
2018-12-28 12:10:28 +01:00
QVERIFY(pushdata1Stack == directStack);
2020-04-11 18:35:43 +02:00
QCOMPARE(state.errorString(), "No error");
2011-07-31 20:01:31 +02:00
std::vector<std::vector<unsigned char> > pushdata2Stack;
2020-04-11 18:35:43 +02:00
state = Script::State(SCRIPT_VERIFY_P2SH);
QVERIFY(Script::eval(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), BaseSignatureChecker(), state));
2018-12-28 12:10:28 +01:00
QVERIFY(pushdata2Stack == directStack);
2020-04-11 18:35:43 +02:00
QCOMPARE(state.errorString(), "No error");
2011-07-31 20:01:31 +02:00
std::vector<std::vector<unsigned char> > pushdata4Stack;
2020-04-11 18:35:43 +02:00
state = Script::State(SCRIPT_VERIFY_P2SH);
QVERIFY(Script::eval(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), BaseSignatureChecker(), state));
2018-12-28 12:10:28 +01:00
QVERIFY(pushdata4Stack == directStack);
2020-04-11 18:35:43 +02:00
QCOMPARE(state.errorString(), "No error");
2011-07-31 20:01:31 +02:00
}
2022-07-06 22:12:33 +02:00
CScript TestScript::sign_multisig(CScript scriptPubKey, std::vector<PrivateKey> keys, CTransaction transaction)
2011-08-26 18:41:22 -04:00
{
2021-01-20 19:21:53 +01:00
const int64_t amountZero = 0;
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, amountZero, SIGHASH_ALL);
2011-08-26 18:41:22 -04:00
CScript result;
//
// NOTE: CHECKMULTISIG has an unfortunate bug; it requires
// one extra item on the stack, before the signatures.
// Putting OP_0 on the stack is the workaround;
2012-10-05 19:22:21 +02:00
// fixing the bug would mean splitting the block chain (old
2011-08-26 18:41:22 -04:00
// clients would not accept new CHECKMULTISIG transactions,
// and vice-versa)
//
result << OP_0;
2022-07-06 22:12:33 +02:00
for (const PrivateKey &key : keys)
2011-08-26 18:41:22 -04:00
{
std::vector<unsigned char> vchSig;
2021-04-19 15:45:02 +02:00
bool ok = key.signECDSA(hash, vchSig);
Q_ASSERT(ok);
2011-08-26 18:41:22 -04:00
vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig;
}
return result;
}
2018-12-28 12:10:28 +01:00
2022-07-06 22:12:33 +02:00
CScript TestScript::sign_multisig(CScript scriptPubKey, const PrivateKey &key, CTransaction transaction)
2011-08-26 18:41:22 -04:00
{
2022-07-06 22:12:33 +02:00
std::vector<PrivateKey> keys;
2011-08-26 18:41:22 -04:00
keys.push_back(key);
return sign_multisig(scriptPubKey, keys, transaction);
}
2018-12-28 12:10:28 +01:00
void TestScript::script_CHECKMULTISIG12()
2011-08-26 18:41:22 -04:00
{
2022-07-06 22:12:33 +02:00
PrivateKey key1, key2, key3;
2022-05-11 13:46:15 +02:00
key1.makeNewKey(true);
key2.makeNewKey(false);
key3.makeNewKey(true);
2011-08-26 18:41:22 -04:00
CScript scriptPubKey12;
2022-05-11 13:46:15 +02:00
scriptPubKey12 << OP_1 << ToByteVector(key1.getPubKey()) << ToByteVector(key2.getPubKey()) << OP_2 << OP_CHECKMULTISIG;
2011-08-26 18:41:22 -04:00
2014-09-28 06:33:33 +02:00
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
2011-08-26 18:41:22 -04:00
2020-04-11 18:35:43 +02:00
Script::State state(flags);
2011-08-26 18:41:22 -04:00
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
2020-04-11 18:35:43 +02:00
bool ok = Script::verify(goodsig1, scriptPubKey12, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), state);
QCOMPARE(state.errorString(), "No error");
2018-12-28 12:10:28 +01:00
QVERIFY(ok);
2011-08-26 18:41:22 -04:00
txTo12.vout[0].nValue = 2;
2020-04-11 18:35:43 +02:00
ok = Script::verify(goodsig1, scriptPubKey12, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
2018-12-28 12:10:28 +01:00
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
2020-04-11 18:35:43 +02:00
QVERIFY(Script::verify(goodsig2, scriptPubKey12, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), state));
QCOMPARE(state.errorString(), "No error");
2011-08-26 18:41:22 -04:00
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
2020-04-11 18:35:43 +02:00
QVERIFY(!Script::verify(badsig1, scriptPubKey12, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), state));
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
2011-08-26 18:41:22 -04:00
}
2018-12-28 12:10:28 +01:00
void TestScript::script_CHECKMULTISIG23()
2011-08-26 18:41:22 -04:00
{
2022-07-06 22:12:33 +02:00
PrivateKey key1, key2, key3, key4;
2022-05-11 13:46:15 +02:00
key1.makeNewKey(true);
key2.makeNewKey(false);
key3.makeNewKey(true);
key4.makeNewKey(false);
2011-08-26 18:41:22 -04:00
CScript scriptPubKey23;
2022-05-11 13:46:15 +02:00
scriptPubKey23 << OP_2 << ToByteVector(key1.getPubKey()) << ToByteVector(key2.getPubKey()) << ToByteVector(key3.getPubKey()) << OP_3 << OP_CHECKMULTISIG;
2011-08-26 18:41:22 -04:00
2014-09-28 06:33:33 +02:00
CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23);
CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23);
2011-08-26 18:41:22 -04:00
2022-07-06 22:12:33 +02:00
std::vector<PrivateKey> keys;
2011-08-26 18:41:22 -04:00
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
Script::State state(flags);
bool ok = Script::verify(goodsig1, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), "No error");
QVERIFY(ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(goodsig2, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), "No error");
QVERIFY(ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(goodsig3, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), "No error");
QVERIFY(ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig1, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig2, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig3, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig4, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig5, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_EVAL_FALSE));
QVERIFY(!ok);
2011-08-26 18:41:22 -04:00
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
2020-04-11 18:35:43 +02:00
ok = Script::verify(badsig6, scriptPubKey23, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), state);
QCOMPARE(state.errorString(), ScriptErrorString(SCRIPT_ERR_INVALID_STACK_OPERATION));
QVERIFY(!ok);
2015-07-30 19:56:00 -04:00
}
2011-08-26 18:41:22 -04:00
2018-12-28 12:10:28 +01:00
void TestScript::script_standard_push()
{
for (int i=0; i<67000; i++) {
2020-04-11 18:35:43 +02:00
Script::State state(SCRIPT_VERIFY_MINIMALDATA);
CScript script;
script << i;
2018-12-28 12:10:28 +01:00
QVERIFY(script.IsPushOnly());
2020-04-11 18:35:43 +02:00
QVERIFY(Script::verify(script, CScript() << OP_1, BaseSignatureChecker(), state));
QCOMPARE(state.errorString(), "No error");
}
for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {
std::vector<unsigned char> data(i, '\111');
2020-04-11 18:35:43 +02:00
Script::State state(SCRIPT_VERIFY_MINIMALDATA);
CScript script;
script << data;
2018-12-28 12:10:28 +01:00
QVERIFY(script.IsPushOnly());
2020-04-11 18:35:43 +02:00
QVERIFY(Script::verify(script, CScript() << OP_1, BaseSignatureChecker(), state));
QCOMPARE(state.errorString(), "No error");
}
}
2018-12-28 12:10:28 +01:00
void TestScript::script_IsPushOnly_on_invalid_scripts()
2014-08-24 21:16:51 -04:00
{
// IsPushOnly returns false when given a script containing only pushes that
// are invalid due to truncation. IsPushOnly() is consensus critical
// because P2SH evaluation uses it, although this specific behavior should
// not be consensus critical as the P2SH evaluation would fail first due to
// the invalid push. Still, it doesn't hurt to test it explicitly.
static const unsigned char direct[] = { 1 };
2018-12-28 12:10:28 +01:00
QVERIFY(!CScript(direct, direct+sizeof(direct)).IsPushOnly());
2014-08-24 21:16:51 -04:00
}
2018-12-28 12:10:28 +01:00
void TestScript::script_GetScriptAsm()
2015-07-30 19:56:00 -04:00
{
2018-12-28 12:10:28 +01:00
const std::string OpCheckLocktimeVerify("OP_CHECKLOCKTIMEVERIFY");
QCOMPARE(OpCheckLocktimeVerify, ScriptToAsmStr(CScript() << OP_NOP2, true));
QCOMPARE(OpCheckLocktimeVerify, ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));
QCOMPARE(OpCheckLocktimeVerify, ScriptToAsmStr(CScript() << OP_NOP2));
QCOMPARE(OpCheckLocktimeVerify, ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
2015-07-30 19:56:00 -04:00
std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");
std::string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");
std::vector<unsigned char> vchPubKey = ToByteVector(ParseHex(pubKey));
2015-07-30 19:56:00 -04:00
2018-12-28 12:10:28 +01:00
QCOMPARE(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true));
QCOMPARE(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true));
QCOMPARE(derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true));
QCOMPARE(derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true));
QCOMPARE(derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true));
QCOMPARE(derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true));
2015-07-30 19:56:00 -04:00
2018-12-28 12:10:28 +01:00
QCOMPARE(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey));
QCOMPARE(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey));
QCOMPARE(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey));
QCOMPARE(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey));
QCOMPARE(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey));
QCOMPARE(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey));
QCOMPARE(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey));
QCOMPARE(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey));
2017-07-24 22:40:28 +02:00
2018-12-28 12:10:28 +01:00
QCOMPARE(derSig + "[NONE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "42")) << vchPubKey, true));
QCOMPARE(derSig + "[NONE|ANYONECANPAY|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c2")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "43")) << vchPubKey, true));
QCOMPARE(derSig + "[SINGLE|ANYONECANPAY|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c3")) << vchPubKey, true));
2015-07-30 19:56:00 -04:00
}
2018-12-28 12:10:28 +01:00
void TestScript::minimize_big_endian_test()
{
2018-04-16 11:59:19 +02:00
// Empty array case
2018-12-28 12:10:28 +01:00
QVERIFY(MinimalizeBigEndianArray(std::vector<uint8_t>()) == std::vector<uint8_t>());
2018-04-16 11:59:19 +02:00
// Zero arrays of various lengths
std::vector<uint8_t> zeroArray({0x00});
std::vector<uint8_t> negZeroArray({0x80});
for (int i = 0; i < 16; i++) {
if (i > 0) {
zeroArray.push_back(0x00);
negZeroArray.push_back(0x00);
}
2018-12-28 12:10:28 +01:00
QVERIFY(MinimalizeBigEndianArray(zeroArray) == std::vector<uint8_t>());
2018-04-16 11:59:19 +02:00
// -0 should always evaluate to 0x00
2018-12-28 12:10:28 +01:00
QVERIFY(MinimalizeBigEndianArray(negZeroArray) == std::vector<uint8_t>());
2018-04-16 11:59:19 +02:00
}
// Shouldn't minimalize this array to a negative number
std::vector<uint8_t> notNegArray({{0x00, 0x80}});
std::vector<uint8_t> notNegArrayPadded({{0x00, 0x80}});
for (int i = 0; i < 16; i++) {
notNegArray.push_back(i);
notNegArrayPadded.insert(notNegArrayPadded.begin(), 0x00);
2018-12-28 12:10:28 +01:00
QVERIFY(MinimalizeBigEndianArray(notNegArray) == notNegArray);
QVERIFY(MinimalizeBigEndianArray(notNegArrayPadded) == std::vector<uint8_t>({{0x00, 0x80}}));
2018-04-16 11:59:19 +02:00
}
// Shouldn't minimalize these arrays at all
std::vector<uint8_t> noMinArray;
for (int i = 1; i < 0x80; i++) {
noMinArray.push_back(i);
2018-12-28 12:10:28 +01:00
QVERIFY(MinimalizeBigEndianArray(noMinArray) == noMinArray);
2018-04-16 11:59:19 +02:00
}
}
void TestScript::minimalPush()
{
// Ensure that CheckMinimalPush always return true for non "pushing" opcodes
std::vector<uint8_t> dummy{};
for (const auto opcode : {OP_1NEGATE, OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_7, OP_8, OP_9, OP_10, OP_11, OP_12,
OP_13, OP_14, OP_15, OP_16})
{
QCOMPARE(CheckMinimalPush(dummy, opcode), true);
}
// Ensure that CheckMinimalPush return false in case we are try use a push opcodes operator whereas
// we should have use OP_0 instead (i.e. data array is empty array)
for (const auto opcode_b : {OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4})
{
QCOMPARE(CheckMinimalPush(dummy, opcode_b), false);
}
// If data.size() is equal to 1 we should have used OP_1 .. OP_16.
dummy = {0};
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA4), false);
// Initialize the vector s to that its size is between 2 and 75
for (int i = 0; i <= 10; i++)
{
dummy.push_back(1);
}
// In this case we should a direct push (opcode indicating number of bytes pushed + those bytes)
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA4), false);
// extend it to have the length between 76 and 255
for (int i = 11; i < 240; i++)
{
dummy.push_back(1);
}
// in this case we must have used OP_PUSHDATA1
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA4), false);
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA1), true);
// extend it to have the length between 256 and 65535
for (int i = 241; i < 300; i++)
{
dummy.push_back(1);
}
// in this case we must have used OP_PUSHDATA2
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA4), false);
QCOMPARE(CheckMinimalPush(dummy, OP_PUSHDATA2), true);
}
2026-05-08 22:11:32 +02:00
// the json encodes numbers as base-10, but really really long.
// so this is not the most effecient but it is the least complex
// solution which is good in a unit test.
static ScriptBigNum fromString(const QString &number)
{
QStringView view(number); // a view avoids lots of mallocs
const bool neg = view.startsWith('-');
if (neg)
view = view.slice(1, view.size() - 1);
ScriptBigNum::BigInt num;
while (!view.isEmpty()) {
num *= 10;
num += view.left(1).toInt();
view.slice(1, view.size() - 1);
}
if (neg)
num = -num;
return ScriptBigNum(num);
}
void TestScript::bigInt()
{
QFile file(":/bigint_test_vectors.json");
QVERIFY(file.open(QIODevice::ReadOnly));
QJsonParseError err;
auto doc = QJsonDocument::fromJson(file.readAll(), &err);
QVERIFY(!doc.isNull());
const auto root = doc.object();
const auto numbers_ = root["numbers"];
QVERIFY(numbers_.isArray());
const auto numbers = numbers_.toArray();
struct Op {
QString leaf;
std::function<void(ScriptBigNum &a, const ScriptBigNum &b)> opFunc;
};
QList<Op> operators = {
{"+", [](ScriptBigNum &a, const ScriptBigNum &b) { a.safeAddInPlace(b); }},
{"-", [](ScriptBigNum &a, const ScriptBigNum &b) { a.safeSubInPlace(b); }},
{"*", [](ScriptBigNum &a, const ScriptBigNum &b) { a.safeMulInPlace(b); }},
{"/", [](ScriptBigNum &a, const ScriptBigNum &b) { a /= b; }},
{"%", [](ScriptBigNum &a, const ScriptBigNum &b) { a %= b; }}
};
// ignoring data from json: &, |, ^, &&, ||, <=>, <<, >>, ++, --
for (const auto &phase : operators) {
const auto item = root[phase.leaf];
QVERIFY(item.isArray());
const auto array = item.toArray();
for (int i = 0; i < array.size(); ++i) {
const auto test_ = array.at(i);
QVERIFY(test_.isArray());
const auto test = test_.toArray();
QCOMPARE(test.size(), 3);
QVERIFY(test.at(0).isDouble());
QVERIFY(test.at(1).isDouble());
QVERIFY(test.at(2).isString());
int a1 = test.at(0).toDouble();
QVERIFY(numbers.size() > a1);
QVERIFY(numbers.at(a1).isString());
auto v1 = numbers.at(a1).toString();
int a2 = test.at(1).toDouble();
QVERIFY(numbers.size() > a2);
QVERIFY(numbers.at(a2).isString());
auto v2 = numbers.at(a2).toString();
ScriptBigNum bn = fromString(v1);
try {
phase.opFunc(bn, fromString(v2));
} catch (const std::overflow_error &e) {
QCOMPARE(test.at(2).toString(), "exception");
continue;
}
ScriptBigNum answer = fromString(test.at(2).toString());
QVERIFY(answer == bn);
}
}
}
2026-05-08 22:53:38 +02:00
void TestScript::bigIntVch()
{
QFETCH(int64_t, number);
ScriptBigNum hello(number);
auto exported = hello.getvch();
ScriptBigNum copy(exported, false);
QVERIFY(copy == hello);
}
void TestScript::bigIntVch_data()
{
QTest::addColumn<int64_t>("number");
QTest::newRow("bytes2") << (int64_t) 0x6415;
QTest::newRow("bytes2-neg") << (int64_t) 0x6415 * -1;
QTest::newRow("small") << (int64_t) 10;
QTest::newRow("small-neg") << (int64_t) -10;
QTest::newRow("big") << (int64_t) 0x71539513;
QTest::newRow("big-neg") << (int64_t) 0x71539513 * -1;
}