diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -87,6 +87,7 @@ test/multisig_tests.cpp \ test/net_tests.cpp \ test/netbase_tests.cpp \ + test/op_endian_reverse_tests.cpp \ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1235,6 +1235,22 @@ stacktop(-1) = std::move(n2); } break; + case OP_ENDIAN_REVERSE: { + if (!(flags & SCRIPT_ENABLE_OP_ENDIAN_REVERSE)) { + return set_error(serror, ScriptError::BAD_OPCODE); + } + + // (in -- out) + if (stack.size() < 1) { + return set_error( + serror, ScriptError::INVALID_STACK_OPERATION); + } + + valtype &data = stacktop(-1); + + std::reverse(data.begin(), data.end()); + } break; + // // Conversion operations // diff --git a/src/script/script.h b/src/script/script.h --- a/src/script/script.h +++ b/src/script/script.h @@ -182,6 +182,9 @@ OP_CHECKDATASIG = 0xba, OP_CHECKDATASIGVERIFY = 0xbb, + // additional byte string operations + OP_ENDIAN_REVERSE = 0xbc, + // The first op_code value after all defined opcodes FIRST_UNDEFINED_OP_VALUE, diff --git a/src/script/script.cpp b/src/script/script.cpp --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -232,6 +232,8 @@ return "OP_CHECKDATASIG"; case OP_CHECKDATASIGVERIFY: return "OP_CHECKDATASIGVERIFY"; + case OP_ENDIAN_REVERSE: + return "OP_ENDIAN_REVERSE"; // expansion case OP_NOP1: diff --git a/src/script/script_flags.h b/src/script/script_flags.h --- a/src/script/script_flags.h +++ b/src/script/script_flags.h @@ -105,6 +105,9 @@ // Whether to allow new OP_CHECKMULTISIG logic to trigger. (new multisig // logic verifies faster, and only allows Schnorr signatures) SCRIPT_ENABLE_SCHNORR_MULTISIG = (1U << 21), + + // Whether the new OP_ENDIAN_REVERSE opcode can be used. + SCRIPT_ENABLE_OP_ENDIAN_REVERSE = (1U << 23), }; #endif // BITCOIN_SCRIPT_SCRIPT_FLAGS_H diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -107,6 +107,7 @@ multisig_tests.cpp net_tests.cpp netbase_tests.cpp + op_endian_reverse_tests.cpp pmt_tests.cpp policyestimator_tests.cpp pow_tests.cpp diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -254,8 +254,8 @@ ["0", "IF CHECKDATASIG ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF CHECKDATASIGVERIFY ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], -["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes >= FIRST_UNDEFINED_OP_VALUE invalid if executed"], -["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF ENDIAN_REVERSE ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], +["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes >= FIRST_UNDEFINED_OP_VALUE invalid if executed"], ["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], ["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"], @@ -961,6 +961,39 @@ "P2SH,STRICTENC", "OK", "SPLIT, maximum length with empty string" ], +["ENDIAN_REVERSE"], +["0", "ENDIAN_REVERSE 0 EQUAL", "P2SH", "BAD_OPCODE", "ENDIAN_REVERSE, not yet activated in executed branch"], +["0x02 0xbeef", "ENDIAN_REVERSE 0x02 0xefbe EQUAL", "P2SH", "BAD_OPCODE", "ENDIAN_REVERSE, not yet activated in executed branch"], +["0", "ENDIAN_REVERSE 0 EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, empty data"], +["0x01 0x99", "ENDIAN_REVERSE 0x01 0x99 EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 1 byte"], +["0x02 0xbeef", "ENDIAN_REVERSE 0x02 0xefbe EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 2 bytes"], +["0x03 0xdeada1", "ENDIAN_REVERSE 0x03 0xa1adde EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 3 bytes"], +["0x04 0xdeadbeef", "ENDIAN_REVERSE 0x04 0xefbeadde EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 4 bytes"], +["'Bitcoin:_A_peer-to-peer_electronic_cash_system'", "ENDIAN_REVERSE 'metsys_hsac_cinortcele_reep-ot-reep_A_:nioctiB' EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, whitepaper title"], +[ + "'zngyivniryrgefgnvqwfwqplmramujzilzyrsdvinxfkfmuowdpuzycnzbupwwpzrfxsbyrhdlsyixyzysodseayvvrtbsfxtikrjwkbduulrjyjlwlaigomhyohsukawdwbrpuacdijzzgxhataguajvuopuktvtklwhsxqvzzfttpdgnxtnbpsiqecxurlczqmoxznlsuejvneiyejetcxlblzrydscnrbydnqytorstjtuzlbbtbyzfiniuehbisqnqhvexylhohjiyiknzgjowvobsrwcxyfowqcvakgdolwpltfcxtrhuysrrvtprzpsucgogsjapdkrbobpxccqgkdumskaleycwsbkabdkuukqiyizceduplmauszwjdzptvmthxocwrignxjogxsvrsjrrlecvdmazlpfkgmskiqqitrevuwiisvpxvkeypzaqjwwiozvmahmtvtjpbolwrymvzfstopzcexalirwbbcqgjvfjfuirrcnlgcfyqnafhh'", + "ENDIAN_REVERSE 'hhfanqyfcglncrriufjfvjgqcbbwrilaxeczpotsfzvmyrwlobpjtvtmhamvzoiwwjqazpyekvxpvsiiwuvertiqqiksmgkfplzamdvcelrrjsrvsxgojxngirwcoxhtmvtpzdjwzsuamlpudecziyiqkuukdbakbswcyelaksmudkgqccxpbobrkdpajsgogcuspzrptvrrsyuhrtxcftlpwlodgkavcqwofyxcwrsbovwojgznkiyijhohlyxevhqnqsibheuinifzybtbblzutjtsrotyqndybrncsdyrzlblxctejeyienvjeuslnzxomqzclruxceqispbntxngdpttfzzvqxshwlktvtkupouvjaugatahxgzzjidcauprbwdwakushoyhmogialwljyjrluudbkwjrkitxfsbtrvvyaesdosyzyxiysldhrybsxfrzpwwpubzncyzupdwoumfkfxnivdsryzlizjumarmlpqwfwqvngfegryrinviygnz' EQUAL", + "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 520 bytes" +], +["0x03 0x123456", "ENDIAN_REVERSE 0x03 0x563412 OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 3 bytes equal"], +["0x06 0x020406080a0c", "DUP ENDIAN_REVERSE ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, 3 bytes double reverse equal"], +["'Bitcoin:_A_peer-to-peer_electronic_cash_system'", "DUP ENDIAN_REVERSE ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, whitepaper title double reverse equal"], +[ + "'zngyivniryrgefgnvqwfwqplmramujzilzyrsdvinxfkfmuowdpuzycnzbupwwpzrfxsbyrhdlsyixyzysodseayvvrtbsfxtikrjwkbduulrjyjlwlaigomhyohsukawdwbrpuacdijzzgxhataguajvuopuktvtklwhsxqvzzfttpdgnxtnbpsiqecxurlczqmoxznlsuejvneiyejetcxlblzrydscnrbydnqytorstjtuzlbbtbyzfiniuehbisqnqhvexylhohjiyiknzgjowvobsrwcxyfowqcvakgdolwpltfcxtrhuysrrvtprzpsucgogsjapdkrbobpxccqgkdumskaleycwsbkabdkuukqiyizceduplmauszwjdzptvmthxocwrignxjogxsvrsjrrlecvdmazlpfkgmskiqqitrevuwiisvpxvkeypzaqjwwiozvmahmtvtjpbolwrymvzfstopzcexalirwbbcqgjvfjfuirrcnlgcfyqnafhh'", + "DUP ENDIAN_REVERSE ENDIAN_REVERSE OP_EQUAL", + "P2SH,ENDIAN_REVERSE", + "OK", + "ENDIAN_REVERSE, 520 bytes double reverse equal" +], +["0x05 0x0102030201", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 1"], +["0x08 0x7766554444556677", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 2"], +["'madam'", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 3"], +["'racecar'", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 4"], +["'redrum_siris_murder'", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 5"], +["'step_on_no_pets'", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "OK", "ENDIAN_REVERSE, palindrome 6"], +["'Bitcoin:_A_peer-to-peer_electronic_cash_system'", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "EVAL_FALSE", "ENDIAN_REVERSE, non-palindrome 1"], +["0x02 0x1234", "DUP ENDIAN_REVERSE OP_EQUAL", "P2SH,ENDIAN_REVERSE", "EVAL_FALSE", "ENDIAN_REVERSE, non-palindrome 2"], + ["NUM2BIN"], ["", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "NUM2BIN, empty stack"], ["0", "NUM2BIN 0 EQUAL", "P2SH,STRICTENC", "INVALID_STACK_OPERATION", "NUM2BIN, one parameter"], @@ -1241,8 +1274,7 @@ "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS", "Discouraged NOP10 in redeemScript"], ["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"], -["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes >= FIRST_UNDEFINED_OP_VALUE invalid if executed"], -["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], +["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes >= FIRST_UNDEFINED_OP_VALUE invalid if executed"], ["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], @@ -1362,7 +1394,7 @@ ["1","RESERVED", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED is reserved"], ["1","RESERVED1", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED1 is reserved"], ["1","RESERVED2", "P2SH,STRICTENC", "BAD_OPCODE", "OP_RESERVED2 is reserved"], -["1","0xbc", "P2SH,STRICTENC", "BAD_OPCODE", "0xbc == FIRST_UNDEFINED_OP_VALUE"], +["1","0xbd", "P2SH,STRICTENC", "BAD_OPCODE", "0xbd == FIRST_UNDEFINED_OP_VALUE"], ["2147483648", "1ADD 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], ["2147483648", "NEGATE 1", "P2SH,STRICTENC", "UNKNOWN_ERROR", "We cannot do math on 5-byte integers"], diff --git a/src/test/op_endian_reverse_tests.cpp b/src/test/op_endian_reverse_tests.cpp new file mode 100644 --- /dev/null +++ b/src/test/op_endian_reverse_tests.cpp @@ -0,0 +1,129 @@ +// Copyright (c) 2020 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include