Skip to content

Commit 358a1bb

Browse files
committed
Add OP_DETERMINISTICRANDOM
1 parent 5a18be3 commit 358a1bb

File tree

5 files changed

+59
-4
lines changed

5 files changed

+59
-4
lines changed

src/script/interpreter.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,61 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
10711071
}
10721072
break;
10731073

1074+
case OP_DETERMINISTICRANDOM:
1075+
{
1076+
if (stack.size() < 3)
1077+
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
1078+
1079+
valtype vchSeed = stacktop(-3);
1080+
CScriptNum bnMin(stacktop(-2), fRequireMinimal);
1081+
CScriptNum bnMax(stacktop(-1), fRequireMinimal);
1082+
1083+
if (bnMin > bnMax)
1084+
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
1085+
1086+
if (bnMin == bnMax) {
1087+
popstack(stack);
1088+
popstack(stack);
1089+
popstack(stack);
1090+
stack.push_back(bnMin.getvch());
1091+
break;
1092+
}
1093+
1094+
// The range of the random source must be a multiple of the modulus
1095+
// to give every possible output value an equal possibility
1096+
uint64_t nMax = (bnMax-bnMin).getint();
1097+
uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
1098+
uint64_t nRand;
1099+
1100+
valtype vchHash(32, 0);
1101+
uint64_t nCounter = 0;
1102+
int nHashIndex = 3;
1103+
CSHA256 hasher;
1104+
hasher.Write(vchSeed.data(), vchSeed.size());
1105+
do {
1106+
if (nHashIndex >= 3) {
1107+
//TODO this isn't endian safe
1108+
CSHA256(hasher).Write((const unsigned char*)&nCounter, sizeof(nCounter)).Finalize(vchHash.data());
1109+
nHashIndex = 0;
1110+
nCounter++;
1111+
}
1112+
1113+
nRand = 0;
1114+
for (size_t i=0; i<8; ++i)
1115+
nRand |= ((uint64_t)vchHash[(nHashIndex*8) + i]) << (8*i);
1116+
1117+
nHashIndex++;
1118+
} while (nRand > nRange);
1119+
CScriptNum result(nRand % nMax);
1120+
result += bnMin.getint();
1121+
1122+
popstack(stack);
1123+
popstack(stack);
1124+
popstack(stack);
1125+
stack.push_back(result.getvch());
1126+
}
1127+
break;
1128+
10741129
default:
10751130
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
10761131
}

src/script/script.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ const char* GetOpName(opcodetype opcode)
126126
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
127127
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
128128
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
129+
case OP_DETERMINISTICRANDOM : return "OP_DETERMINISTICRANDOM";
129130

130131
// expansion
131132
case OP_NOP1 : return "OP_NOP1";

src/script/script.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ enum opcodetype
173173
OP_CHECKSIGVERIFY = 0xad,
174174
OP_CHECKMULTISIG = 0xae,
175175
OP_CHECKMULTISIGVERIFY = 0xaf,
176+
OP_DETERMINISTICRANDOM = 0xc0,
176177

177178
// expansion
178179
OP_NOP1 = 0xb0,
@@ -192,7 +193,7 @@ enum opcodetype
192193
};
193194

194195
// Maximum value that an opcode can be
195-
static const unsigned int MAX_OPCODE = OP_NOP10;
196+
static const unsigned int MAX_OPCODE = OP_DETERMINISTICRANDOM;
196197

197198
const char* GetOpName(opcodetype opcode);
198199

src/test/data/script_tests.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,6 @@
258258
["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
259259
["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
260260
["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
261-
["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
262261
["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
263262
["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
264263
["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
@@ -894,7 +893,6 @@
894893
["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
895894
["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
896895
["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
897-
["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
898896
["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
899897
["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],
900898
["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"],

src/test/script_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps)
14741474
BOOST_CHECK(script.HasValidOps());
14751475
script = ScriptFromHex("ff88ac"); // Script with OP_INVALIDOPCODE explicit
14761476
BOOST_CHECK(!script.HasValidOps());
1477-
script = ScriptFromHex("88acc0"); // Script with undefined opcode
1477+
script = ScriptFromHex("88acc1"); // Script with undefined opcode: one higher then MAX_OPCODE
14781478
BOOST_CHECK(!script.HasValidOps());
14791479
}
14801480

0 commit comments

Comments
 (0)