/** * @param $opCode * @param ScriptStack $mainStack * @param ScriptStack $vfStack * @param $fExec * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ public function op($opCode, ScriptStack $mainStack, ScriptStack $vfStack, $fExec) { $opCodes = $this->opCodes; $castToBool = $this->castToBool; $opName = $opCodes->getOp($opCode); if ($opName == 'OP_NOP') { return; } elseif (in_array($opName, ['OP_IF', 'OP_NOTIF'])) { // cscriptnum // <expression> if [statements] [else [statements]] endif $value = false; if ($fExec) { if ($mainStack->size() < 1) { throw new \Exception('Unbalanced conditional'); } // todo $buffer = $mainStack->pop(); $value = $castToBool($buffer); if ($opCodes->isOp($opCode, 'OP_NOTIF')) { $value = !$value; } } $vfStack->push($value); return; } else { if ($opName == 'OP_ELSE') { if ($vfStack->size() == 0) { throw new \Exception('Unbalanced conditional'); } $vfStack->set($vfStack->end() - 1, !$vfStack->end()); return; } else { if ($opName == 'OP_ENDIF') { if ($vfStack->size() == 0) { throw new \Exception('Unbalanced conditional'); } // todo return; } else { if ($opName == 'OP_VERIFY') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation'); } $value = $castToBool($mainStack->top(-1)); if (!$value) { throw new \Exception('Error: verify'); } $mainStack->pop(); return; } else { if ($opName == 'OP_RETURN') { throw new \Exception('Error: OP_RETURN'); } } } } } throw new \Exception('Opcode not found'); }
/** * @param $opCode * @param ScriptStack $mainStack * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ public function op($opCode, ScriptStack $mainStack) { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation'); } $opCodes = $this->opCodes; $opName = $opCodes->getOp($opCode); $buffer = $mainStack->top(-1); if ($opCodes->cmp($opCode, 'OP_RIPEMD160') >= 0 && $opCodes->cmp($opCode, 'OP_HASH256') <= 0) { if ($opName == 'OP_RIPEMD160') { $hash = Hash::ripemd160($buffer); } elseif ($opName == 'OP_SHA1') { $hash = Hash::sha1($buffer); } elseif ($opName == 'OP_SHA256') { $hash = Hash::sha256($buffer); } elseif ($opName == 'OP_HASH160') { $hash = Hash::sha256ripe160($buffer); } else { // is hash256 $hash = Hash::sha256d($buffer); } $mainStack->pop(); $mainStack->push($hash); } else { throw new \Exception('Opcode not found'); } }
/** * @param $opCode * @param ScriptStack $mainStack * @param ScriptStack $altStack * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ public function op($opCode, ScriptStack $mainStack, ScriptStack $altStack) { $opCodes = $this->opCodes; $opName = $this->opCodes->getOp($opCode); $castToBool = $this->castToBool; if ($opName == 'OP_TOALTSTACK') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_TOALTSTACK'); } $altStack->push($mainStack->pop()); return; } else { if ($opName == 'OP_FROMALTSTACK') { if ($altStack->size() < 1) { throw new \Exception('Invalid alt-stack operation OP_FROMALTSTACK'); } $mainStack->push($altStack->pop()); return; } else { if ($opName == 'OP_IFDUP') { // If top value not zero, duplicate it. if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_IFDUP'); } $vch = $mainStack->top(-1); if ($castToBool($vch)) { $mainStack->push($vch); } return; } else { if ($opName == 'OP_DEPTH') { $num = $mainStack->size(); $bin = Buffer::hex($this->math->decHex($num)); $mainStack->push($bin); return; } else { if ($opName == 'OP_DROP') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_DROP'); } $mainStack->pop(); return; } else { if ($opName == 'OP_DUP') { if ($mainStack->size() < 1) { throw new \Exception('Invalid stack operation OP_DUP'); } $vch = $mainStack->top(-1); $mainStack->push($vch); return; } else { if ($opName == 'OP_NIP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_NIP'); } $mainStack->erase(-2); return; } else { if ($opName == 'OP_OVER') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_OVER'); } $vch = $mainStack->top(-2); $mainStack->push($vch); return; } else { if (in_array($opName, ['OP_PICK', 'OP_ROLL'])) { // cscriptnum if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_PICK'); } $n = $mainStack->top(-1)->getInt(); $mainStack->pop(); if ($this->math->cmp($n, 0) < 0 || $this->math->cmp($n, $mainStack->size()) >= 0) { throw new \Exception('Invalid stack operation OP_PICK'); } $pos = $this->math->sub($this->math->sub(0, $n), 1); $vch = $mainStack->top($pos); if ($opCodes->isOp($opCode, 'OP_ROLL')) { $mainStack->erase($pos); } $mainStack->push($vch); return; } else { if ($opName == 'OP_ROT') { if ($mainStack->size() < 3) { throw new \Exception('Invalid stack operation OP_ROT'); } $mainStack->swap(-3, -2); $mainStack->swap(-2, -1); return; } else { if ($opName == 'OP_SWAP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_SWAP'); } $mainStack->swap(-2, -1); return; } else { if ($opName == 'OP_TUCK') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_TUCK'); } $vch = $mainStack->top(-1); $mainStack->insert($mainStack->end() - 2, $vch); return; } else { if ($opName == 'OP_2DROP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_2DROP'); } $mainStack->pop(); $mainStack->pop(); return; } else { if ($opName == 'OP_2DUP') { if ($mainStack->size() < 2) { throw new \Exception('Invalid stack operation OP_2DUP'); } $string1 = $mainStack->top(-2); $string2 = $mainStack->top(-1); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_3DUP') { if ($mainStack->size() < 3) { throw new \Exception('Invalid stack operation OP_3DUP'); } $string1 = $mainStack->top(-3); $string2 = $mainStack->top(-2); $string3 = $mainStack->top(-1); $mainStack->push($string1); $mainStack->push($string2); $mainStack->push($string3); return; } else { if ($opName == 'OP_2OVER') { if ($mainStack->size() < 4) { throw new \Exception('Invalid stack operation OP_2OVER'); } $string1 = $mainStack->top(-4); $string2 = $mainStack->top(-3); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_2ROT') { if ($mainStack->size() < 6) { throw new \Exception('Invalid stack operation OP_2ROT'); } $string1 = $mainStack->top(-6); $string2 = $mainStack->top(-5); $mainStack->erase(-6); $mainStack->erase(-5); $mainStack->push($string1); $mainStack->push($string2); return; } else { if ($opName == 'OP_2SWAP') { if ($mainStack->size() < 4) { throw new \Exception('Invalid stack operation OP_2SWAP'); } $mainStack->swap(-3, -1); $mainStack->swap(-4, -2); return; } } } } } } } } } } } } } } } } } } throw new \Exception('Opcode not found'); }
/** * @param $opCode * @param ScriptStack $mainStack * @throws \BitWasp\Bitcoin\Exceptions\ScriptStackException * @throws \Exception */ private function threeValueCases($opCode, ScriptStack $mainStack) { $opName = $this->opCodes->getOp($opCode); $math = $this->math; if ($opName == 'OP_WITHIN') { //cscriptnum if ($mainStack->size() < 3) { throw new \Exception('Invalid stack operation'); } $num1 = $mainStack->top(-3)->getInt(); $num2 = $mainStack->top(-2)->getInt(); $num3 = $mainStack->top(-1)->getInt(); $value = $math->cmp($num2, $num1) <= 0 && $math->cmp($num1, $num3) < 0; $mainStack->pop(); $mainStack->pop(); $mainStack->pop(); $mainStack->push($value ? $this->_bn1 : $this->_bn0); return; } throw new \Exception('Opcode not found'); }