diff options
-rw-r--r-- | src/core_io.h | 1 | ||||
-rw-r--r-- | src/core_write.cpp | 35 | ||||
-rw-r--r-- | src/key.cpp | 8 | ||||
-rw-r--r-- | src/key.h | 2 | ||||
-rw-r--r-- | src/test/data/script_invalid.json | 24 | ||||
-rw-r--r-- | src/test/data/script_valid.json | 25 | ||||
-rw-r--r-- | src/test/script_tests.cpp | 325 | ||||
-rw-r--r-- | src/test/transaction_tests.cpp | 42 |
8 files changed, 413 insertions, 49 deletions
diff --git a/src/core_io.h b/src/core_io.h index 6268a3bf58..94848f1c3d 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -20,6 +20,7 @@ extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); // core_write.cpp +extern std::string FormatScript(const CScript& script); extern std::string EncodeHexTx(const CTransaction& tx); extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); diff --git a/src/core_write.cpp b/src/core_write.cpp index cd64aabf63..40d547fb33 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -17,6 +17,41 @@ using namespace std; +string FormatScript(const CScript& script) +{ + string ret; + CScript::const_iterator it = script.begin(); + opcodetype op; + while (it != script.end()) { + CScript::const_iterator it2 = it; + vector<unsigned char> vch; + if (script.GetOp2(it, op, &vch)) { + if (op == OP_0) { + ret += "0 "; + continue; + } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { + ret += strprintf("%i ", op - OP_1NEGATE - 1); + continue; + } else if (op >= OP_NOP && op <= OP_CHECKMULTISIGVERIFY) { + string str(GetOpName(op)); + if (str.substr(0, 3) == string("OP_")) { + ret += str.substr(3, string::npos) + " "; + continue; + } + } + if (vch.size() > 0) { + ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); + } else { + ret += strprintf("0x%x", HexStr(it2, it)); + } + continue; + } + ret += strprintf("0x%x ", HexStr(it2, script.end())); + break; + } + return ret.substr(0, ret.size() - 1); +} + string EncodeHexTx(const CTransaction& tx) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/key.cpp b/src/key.cpp index 8ed787654a..c2251b4f2a 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -220,7 +220,7 @@ public: return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size()) != NULL; } - bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) { + bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) { vchSig.clear(); ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); if (sig == NULL) @@ -232,7 +232,7 @@ public: BIGNUM *halforder = BN_CTX_get(ctx); EC_GROUP_get_order(group, order, ctx); BN_rshift1(halforder, order); - if (BN_cmp(sig->s, halforder) > 0) { + if (lowS && BN_cmp(sig->s, halforder) > 0) { // enforce low S values, by negating the value (modulo the order) if above order/2. BN_sub(sig->s, order, sig->s); } @@ -467,7 +467,7 @@ CPubKey CKey::GetPubKey() const { return pubkey; } -bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const { +bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) const { if (!fValid) return false; #ifdef USE_SECP256K1 @@ -484,7 +484,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const { #else CECKey key; key.SetSecretBytes(vch); - return key.Sign(hash, vchSig); + return key.Sign(hash, vchSig, lowS); #endif } @@ -276,7 +276,7 @@ public: CPubKey GetPubKey() const; // Create a DER-serialized signature. - bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig) const; + bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, bool lowS = true) const; // Create a compact signature (65 bytes), which allows reconstructing the used public key. // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 401031ad12..35a6794b01 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -384,18 +384,18 @@ nSequences are max. ["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], -["0x48 0x3045022100ea4d62e1fb351ad977596457bb01dfce58e050541784277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash with wrong signature"], -["0x47 0x304402207d09de5e34968c3f8b27d8217f173629f1106ee5216aa11d6b1f9813b3a214060220610a6ed25c704f901c6278f4f57fb11eadefdf0b22df298cfb6ce7ea84c86bf401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash using an anyonecanpay sighash"], -["0x47 0x3044022028686fb3c8d3e5068cc9924c494fb5026df201d23340896da62fe9bb73fd9d5f02202a239609524959c4ca3651fd0cc48245b0b240862146fc579f3a962a4f46942b01", "0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkey with wrong signature"], -["0x47 0x3044022054cb0a3fca8694a0c231848ed9f965078148fd653e49dd4b6981fadac0f5ba0702204085be5af427d4561f13a07fd5a1c5ab0ff02126e9ba191448f5a9dae0da585301 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x19 0x76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", "HASH160 0x14 0xcd7b44d0b03f2d026d1e586d7ae18903b0d385f6 EQUAL", "P2SH,STRICTENC", "P2SH with a pay to pubkeyhash inside with wrong signature"], -["0 0x48 0x3045022100e1c4e8800bd00c9ec3cd3df0e53e63bc5e8c018d0b68099a652f0b121f1a7e020220108dab275be7d1358530d3451d48aed747af77cc54e0423cbae5c572b2e1abb801", "1 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 1 CHECKMULTISIG", "P2SH,STRICTENC", "Raw multisig with one pubkey with wrong signature"], -["0x49 0x304602220000ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash with non-DER signature (too much R padding)"], -["0x47 0x30440220ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash with non-DER signature (too little R padding)"], -["0x49 0x3046022100ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a950221003003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash with non-DER signature (too much S padding)"], -["0x48 0x3045022100e6eda3fd34862078233463cae19f0b47995e3f892102e5b175175e92a9163cc402204bf58445819093638481084322b61a2d49b68c96fd6fea17ed494722d0d67b4f01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "P2SH,STRICTENC", "Pay to pubkey with hybrid pubkey encoding"], -["0x48 0x304502203b56d65863e0cdb89313043c2402f46f518c31658648151b01ec6b5b6c89206a022100d71efefb4c24fab36abb44ade106963d8114c5af1bda033faa1923f54ec4ea6a01", "0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 CHECKSIG", "P2SH,STRICTENC,LOW_S", "Pay to pubkey with high S"], -["0x47 0x3044022054cb0a3fca8694a0c231848fd9f965078148fd653e49dd4b6980fadac0f5ba0702204085be5af427d4561f13a07fd5a1c5ab0ff02126e9ba191448f5a9dae0da585301 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x19 0x76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", "HASH160 0x14 0xcd7b44d0b03f2d026d1e586d7ae18903b0d385f6 EQUAL", "P2SH,STRICTENC", "P2SH with a pay to pubkeyhash inside with invalid signature"], -["1 0x48 0x3045022100e1c4e8800bd00c9ec3cd3de0e53e63bc5e8c018d0b68099a652f0b121f1a7e020220108dab275be7d1358530d3451d48aed747af77cc54e0423cbae5c572b2e1abb801", "1 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 1 CHECKMULTISIG", "P2SH,STRICTENC,NULLDUMMY", "Raw multisig with one pubkey with non-zero dummy"], +["0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK, bad sig"], +["0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", "", "P2PKH, bad pubkey"], +["0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay marked with normal hashtype"], +["0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK), bad redeemscript"], +["0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "P2SH", "P2SH(P2PKH), bad sig"], +["0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3, 2 sigs"], +["0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3), 1 sig"], +["0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much R padding"], +["0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too much S padding"], +["0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "STRICTENC", "P2PK with too little R padding"], +["0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S,STRICTENC", "P2PK with high S"], +["0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "NULLDUMMY", "3-of-3 with nonzero dummy"], ["The End"] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index e0b527996c..653f60d982 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -529,18 +529,19 @@ nSequences are max. ["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], -["0x48 0x3045022100ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkeyhash"], -["0x47 0x304402207d09de5e34968c3f8b27d8217f173629f1106ee5216aa11d6b1f9813b3a214060220610a6ed25c704f901c6278f4f57fb11eadefdf0b22df298cfb6ce7ea84c86bf481 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH,STRICTENC", "Anyonecanpay pay to pubkeyhash"], -["0x47 0x3044022028686fb3c8d3e5069cc9924c494fb5026df201d23340896da62fe9bb73fd9d5f02202a239609524959c4ca3651fd0cc48245b0b240862146fc579f3a962a4f46942b01", "0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 CHECKSIG", "P2SH,STRICTENC", "Normal pay to pubkey"], -["0x47 0x3044022054cb0a3fca8694a0c231848ed9f965078148fd653e49dd4b6980fadac0f5ba0702204085be5af427d4561f13a07fd5a1c5ab0ff02126e9ba191448f5a9dae0da585301 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x19 0x76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", "HASH160 0x14 0xcd7b44d0b03f2d026d1e586d7ae18903b0d385f6 EQUAL", "P2SH,STRICTENC", "P2SH with a pay to pubkeyhash inside"], -["0 0x48 0x3045022100e1c4e8800bd00c9ec3cd3de0e53e63bc5e8c018d0b68099a652f0b121f1a7e020220108dab275be7d1358530d3451d48aed747af77cc54e0423cbae5c572b2e1abb801", "1 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 1 CHECKMULTISIG", "P2SH,STRICTENC", "Raw multisig with one pubkey"], -["0x49 0x304602220000ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH", "Normal pay to pubkeyhash with non-DER signature (too much R padding)"], -["0x47 0x30440220ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a9502203003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH", "Normal pay to pubkeyhash with non-DER signature (too little R padding)"], -["0x49 0x3046022100ea4d62e1fb351ad977596457bb01dfce58e050541774277bd825c33bd98c2a950221003003347cf04573be4dc786c3fc5e7db09821565bf45c7d60160709b962f0398401 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", "DUP HASH160 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6 EQUALVERIFY CHECKSIG", "P2SH", "Normal pay to pubkeyhash with non-DER signature (too much S padding)"], -["0x48 0x3045022100e6eda3fd34862078233463cae19f0b47995e3f892102e5b175175e92a9163cc402204bf58445819093638481084322b61a2d49b68c96fd6fea17ed494722d0d67b4f01", "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "P2SH", "Pay to pubkey with hybrid pubkey encoding"], -["0x48 0x304502203b56d65863e0cdb89313043c2402f46f518c31658648151b01ec6b5b6c89206a022100d71efefb4c24fab36abb44ade106963d8114c5af1bda033faa1923f54ec4ea6a01", "0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 CHECKSIG", "P2SH,STRICTENC", "Pay to pubkey with high S"], -["0x47 0x3044022054cb0a3fca8694a0c231848fd9f965078148fd653e49dd4b6980fadac0f5ba0702204085be5af427d4561f13a07fd5a1c5ab0ff02126e9ba191448f5a9dae0da585301 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x19 0x76a914751e76e8199196d454941c45d1b3a323f1433bd688ac", "HASH160 0x14 0xcd7b44d0b03f2d026d1e586d7ae18903b0d385f6 EQUAL", "STRICTENC", "P2SH with a pay to pubkeyhash inside with invalid signature"], -["1 0x48 0x3045022100e1c4e8800bd00c9ec3cd3de0e53e63bc5e8c018d0b68099a652f0b121f1a7e020220108dab275be7d1358530d3451d48aed747af77cc54e0423cbae5c572b2e1abb801", "1 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 1 CHECKMULTISIG", "P2SH,STRICTENC", "Raw multisig with one pubkey with non-zero dummy"], +["0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501", "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", "", "P2PK"], +["0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", "", "P2PKH"], +["0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581", "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", "", "P2PK anyonecanpay"], +["0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", "P2SH", "P2SH(P2PK)"], +["0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", "", "P2SH(P2PKH), bad sig but no VERIFY_P2SH"], +["0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3"], +["0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", "P2SH", "P2SH(2-of-3)"], +["0x47 0x304402200001cae94b795baaafb05db38cf24cd75560cab2c36c91e29fac7d0fd2a723a3022058e2e56e568ce7c4b2b106210d114e1faa079407a6ed4154f230667c7d3583bc01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much R padding but no STRICTENC"], +["0x48 0x304502206d01de7c2a40ac2bb1231ed97f3890a1782f421d4c28b97166deff317990288f0221005e720213b089355be2cf785d81a82c59307d30e1624f450ed9ca1ebbc11cca6d01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too much S padding but no STRICTENC"], +["0x47 0x30440220f3d8889602147d60d26c1d3b21b8db183eac02bf6d2fec1424c0ef377ca6fd7b02202bae8bfe39d00a432d4538a592e338b0ffc44c17d4b7056043d55063cf91f5ef01", "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", "", "P2PK with too little R padding but no STRICTENC"], +["0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "STRICTENC", "P2PK with high S but no LOW_S"], +["0x48 0x304502205c3e81aaf2aad0673f349035b180eba783eba7797af91c979920dea6b17a16d6022100d1d46825c68da1b325f320a3503dad27bb818227f64a38d153554bfd360c0e5301", "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", "LOW_S", "P2PK with high S but no STRICTENC"], +["0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01", "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", "", "3-of-3 with nonzero dummy but no NULLDUMMY"], ["The End"] ] diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 178b35fa2d..f9086b6a64 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -5,12 +5,13 @@ #include "data/script_invalid.json.h" #include "data/script_valid.json.h" +#include "core_io.h" #include "key.h" #include "keystore.h" #include "main.h" #include "script/script.h" #include "script/sign.h" -#include "core_io.h" +#include "util.h" #include <fstream> #include <stdint.h> @@ -36,6 +37,7 @@ using namespace boost::algorithm; static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(string strFlags); +string FormatScriptFlags(unsigned int flags); Array read_json(const std::string& jsondata) @@ -68,10 +70,8 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) return txCredit; } -CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScript& scriptPubKey) +CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CTransaction& txCredit) { - CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); - CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; @@ -87,6 +87,317 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSc return txSpend; } +void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) +{ + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0, flags) == expect, message); +} + +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 +{ + CKey key0, key0C, key1, key1C, key2, key2C; + CPubKey pubkey0, pubkey0C, pubkey0H; + CPubKey pubkey1, pubkey1C; + CPubKey pubkey2, pubkey2C; + + KeyData() + { + + key0.Set(&vchKey0[0], &vchKey0[32], false); + key0C.Set(&vchKey0[0], &vchKey0[32], true); + pubkey0 = key0.GetPubKey(); + pubkey0H = key0.GetPubKey(); + pubkey0C = key0C.GetPubKey(); + *const_cast<unsigned char*>(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); + + key1.Set(&vchKey1[0], &vchKey1[32], false); + key1C.Set(&vchKey1[0], &vchKey1[32], true); + pubkey1 = key1.GetPubKey(); + pubkey1C = key1C.GetPubKey(); + + key2.Set(&vchKey2[0], &vchKey2[32], false); + key2C.Set(&vchKey2[0], &vchKey2[32], true); + pubkey2 = key2.GetPubKey(); + pubkey2C = key2C.GetPubKey(); + } +}; + +const KeyData keys; + +class TestBuilder +{ +private: + CScript scriptPubKey; + CTransaction creditTx; + CMutableTransaction spendTx; + bool havePush; + std::vector<unsigned char> push; + std::string comment; + int flags; + + void DoPush() + { + if (havePush) { + spendTx.vin[0].scriptSig << push; + havePush = false; + } + } + + void DoPush(const std::vector<unsigned char>& data) + { + DoPush(); + push = data; + havePush = true; + } + +public: + TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) + { + if (P2SH) { + creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << redeemScript.GetID() << OP_EQUAL); + } else { + creditTx = BuildCreditingTransaction(redeemScript); + } + spendTx = BuildSpendingTransaction(CScript(), creditTx); + } + + TestBuilder& Add(const CScript& script) + { + spendTx.vin[0].scriptSig += script; + return *this; + } + + TestBuilder& Num(int num) + { + spendTx.vin[0].scriptSig << CScriptNum(num); + return *this; + } + + TestBuilder& Push(const std::string& hex) + { + DoPush(ParseHex(hex)); + return *this; + } + + TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32) + { + uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); + std::vector<unsigned char> vchSig, r, s; + do { + key.Sign(hash, vchSig, lenS <= 32); + r = std::vector<unsigned char>(&vchSig[4], &vchSig[4 + vchSig[3]]); + s = std::vector<unsigned char>(&vchSig[6 + vchSig[3]], &vchSig[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; + } + + TestBuilder& Push(const CPubKey& pubkey) + { + DoPush(std::vector<unsigned char>(pubkey.begin(), pubkey.end())); + return *this; + } + + TestBuilder& PushRedeem() + { + DoPush(static_cast<std::vector<unsigned char> >(scriptPubKey)); + return *this; + } + + TestBuilder& EditPush(unsigned int pos, const std::string& hexin, const std::string& hexout) + { + assert(havePush); + std::vector<unsigned char> datain = ParseHex(hexin); + std::vector<unsigned char> dataout = ParseHex(hexout); + assert(pos + datain.size() <= push.size()); + BOOST_CHECK_MESSAGE(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); + push.erase(push.begin() + pos, push.begin() + pos + datain.size()); + push.insert(push.begin() + pos, dataout.begin(), dataout.end()); + return *this; + } + + TestBuilder& DamagePush(unsigned int pos) + { + assert(havePush); + assert(pos < push.size()); + push[pos] ^= 1; + return *this; + } + + 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); + *this = copy; + return *this; + } + + operator std::string() + { + DoPush(); + return "[\"" + + FormatScript(spendTx.vin[0].scriptSig) + "\", \"" + + FormatScript(creditTx.vout[0].scriptPubKey) + "\", \"" + + FormatScriptFlags(flags) + "\", \"" + + comment + "\"],\n"; + } + + std::string GetComment() + { + return comment; + } + + const CScript& GetScriptPubKey() + { + return creditTx.vout[0].scriptPubKey; + } +}; +} + +BOOST_AUTO_TEST_CASE(script_build) +{ + std::vector<TestBuilder> good; + std::vector<TestBuilder> bad; + + good.push_back(TestBuilder(CScript() << keys.pubkey0 << OP_CHECKSIG, + "P2PK", 0 + ).PushSig(keys.key0)); + bad.push_back(TestBuilder(CScript() << keys.pubkey0 << OP_CHECKSIG, + "P2PK, bad sig", 0 + ).PushSig(keys.key0).DamagePush(10)); + + good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1C.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH", 0 + ).PushSig(keys.key1).Push(keys.pubkey1C)); + bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey2C.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH, bad pubkey", 0 + ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5)); + + good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG, + "P2PK anyonecanpay", 0 + ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); + bad.push_back(TestBuilder(CScript() << 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() << keys.pubkey0C << OP_CHECKSIG, + "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem()); + bad.push_back(TestBuilder(CScript() << keys.pubkey0C << OP_CHECKSIG, + "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem().DamagePush(10)); + + good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true + ).PushSig(keys.key0).DamagePush(10).PushRedeem()); + bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1.GetID() << 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 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much R padding but no STRICTENC", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much R padding", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much S padding but no STRICTENC", 0 + ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much S padding", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); + good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too little R padding but no STRICTENC", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too little R padding", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + + good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG, + "P2PK with high S but no LOW_S", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG, + "P2PK with high S but no STRICTENC", SCRIPT_VERIFY_LOW_S + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG, + "P2PK with high S", SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + + good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << 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 << keys.pubkey0C << keys.pubkey1C << 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)); + + std::map<std::string, Array> tests_good; + std::map<std::string, Array> tests_bad; + + { + Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); + Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); + + BOOST_FOREACH(Value& tv, json_good) { + Array test = tv.get_array(); + if (test.size() >= 4) { + tests_good[test[3].get_str()] = test; + } + } + BOOST_FOREACH(Value& tv, json_bad) { + Array test = tv.get_array(); + if (test.size() >= 4) { + tests_bad[test[3].get_str()] = test; + } + } + } + + std::string strGood; + std::string strBad; + + BOOST_FOREACH(TestBuilder& test, good) { + test.Test(true); + BOOST_CHECK_MESSAGE(tests_good.count(test.GetComment()) > 0, "Missing auto script_valid test: " + test.GetComment()); + BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment()); + strGood += test; + } + BOOST_FOREACH(TestBuilder& test, bad) { + test.Test(false); + BOOST_CHECK_MESSAGE(tests_bad.count(test.GetComment()) > 0, "Missing auto script_invalid test: " + test.GetComment()); + BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment()); + strBad += test; + } + +#if 0 + 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 +} + BOOST_AUTO_TEST_CASE(script_valid) { // Read tests from test/data/script_valid.json @@ -113,8 +424,7 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - CTransaction tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, BuildSpendingTransaction(scriptSig, scriptPubKey), 0, scriptflags), strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); } } @@ -140,8 +450,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - CTransaction tx; - BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, BuildSpendingTransaction(scriptSig, scriptPubKey), 0, scriptflags), strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 41d8ee9f19..83116b51e5 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -17,6 +17,7 @@ #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/test/unit_test.hpp> +#include <boost/assign/list_of.hpp> #include "json/json_spirit_writer_template.h" using namespace std; @@ -26,22 +27,23 @@ using namespace boost::algorithm; // In script_tests.cpp extern Array read_json(const std::string& jsondata); -unsigned int ParseScriptFlags(string strFlags){ +// Note how NOCACHE is not included as it is a runtime-only flag. +static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of + (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) + (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) + (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) + (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) + (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY); + +unsigned int ParseScriptFlags(string strFlags) +{ + if (strFlags.empty()) { + return 0; + } unsigned int flags = 0; vector<string> words; split(words, strFlags, is_any_of(",")); - // Note how NOCACHE is not included as it is a runtime-only flag. - static map<string, unsigned int> mapFlagNames; - if (mapFlagNames.size() == 0) - { - mapFlagNames["NONE"] = SCRIPT_VERIFY_NONE; - mapFlagNames["P2SH"] = SCRIPT_VERIFY_P2SH; - mapFlagNames["STRICTENC"] = SCRIPT_VERIFY_STRICTENC; - mapFlagNames["LOW_S"] = SCRIPT_VERIFY_LOW_S; - mapFlagNames["NULLDUMMY"] = SCRIPT_VERIFY_NULLDUMMY; - } - BOOST_FOREACH(string word, words) { if (!mapFlagNames.count(word)) @@ -52,6 +54,22 @@ unsigned int ParseScriptFlags(string strFlags){ return flags; } +string FormatScriptFlags(unsigned int flags) +{ + if (flags == 0) { + return ""; + } + string ret; + std::map<string, unsigned int>::const_iterator it = mapFlagNames.begin(); + while (it != mapFlagNames.end()) { + if (flags & it->second) { + ret += it->first + ","; + } + it++; + } + return ret.substr(0, ret.size() - 1); +} + BOOST_AUTO_TEST_SUITE(transaction_tests) BOOST_AUTO_TEST_CASE(tx_valid) |