File Coverage

blib/lib/Bitcoin/Crypto/Script/Opcode.pm
Criterion Covered Total %
statement 55 55 100.0
branch 6 10 60.0
condition n/a
subroutine 18 18 100.0
pod 3 3 100.0
total 82 86 95.3


line stmt bran cond sub pod time code
1             package Bitcoin::Crypto::Script::Opcode;
2             $Bitcoin::Crypto::Script::Opcode::VERSION = '2.000_01'; # TRIAL
3             $Bitcoin::Crypto::Script::Opcode::VERSION = '2.00001';
4 29     29   410 use v5.10;
  29         108  
5 29     29   196 use strict;
  29         80  
  29         648  
6 29     29   178 use warnings;
  29         82  
  29         820  
7              
8 29     29   184 use Moo;
  29         87  
  29         258  
9 29     29   12676 use Mooish::AttributeBuilder -standard;
  29         96  
  29         265  
10              
11 29     29   3855 use Crypt::Digest::RIPEMD160 qw(ripemd160);
  29         80  
  29         1719  
12 29     29   235 use Crypt::Digest::SHA256 qw(sha256);
  29         88  
  29         1548  
13 29     29   13721 use Crypt::Digest::SHA1 qw(sha1);
  29         19250  
  29         1792  
14              
15 29     29   3972 use Bitcoin::Crypto qw(btc_pub);
  29         95  
  29         1306  
16 29     29   194 use Bitcoin::Crypto::Constants;
  29         99  
  29         720  
17 29     29   244 use Bitcoin::Crypto::Exception;
  29         82  
  29         690  
18 29     29   181 use Bitcoin::Crypto::Types qw(Str StrLength CodeRef Bool);
  29         91  
  29         217  
19 29     29   85564 use Bitcoin::Crypto::Util qw(hash160 hash256 get_public_key_compressed);
  29         79  
  29         1578  
20 29     29   10841 use Bitcoin::Crypto::Transaction::Input;
  29         95  
  29         3275  
21              
22             # some private helpers for opcodes
23              
24             sub stack_error
25             {
26             die 'stack error';
27             }
28              
29             sub invalid_script
30             {
31             Bitcoin::Crypto::Exception::TransactionScript->raise(
32             'transaction was marked as invalid'
33             );
34             }
35              
36             sub script_error
37             {
38             Bitcoin::Crypto::Exception::TransactionScript->raise(
39             shift
40             );
41             }
42              
43 29     29   288 use namespace::clean;
  29         90  
  29         358  
44              
45             has param 'name' => (
46             isa => Str,
47             );
48              
49             has param 'code' => (
50             isa => StrLength [1, 1],
51             );
52              
53             has param 'needs_transaction' => (
54             isa => Bool,
55             default => 0,
56             );
57              
58             has param 'pushes' => (
59             isa => Bool,
60             default => 0,
61             );
62              
63             has option 'runner' => (
64             isa => CodeRef,
65             predicate => 'implemented',
66             );
67              
68             sub execute
69             {
70 822     822 1 1654 my ($self, @args) = @_;
71              
72 822 50       2286 die $self->name . ' is not implemented'
73             unless $self->implemented;
74              
75 822         2720 return $self->runner->(@args);
76             }
77              
78             my %opcodes = (
79             OP_0 => {
80             code => "\x00",
81             pushes => !!1,
82             runner => sub {
83             my $runner = shift;
84              
85             push @{$runner->stack}, '';
86             },
87             },
88             OP_PUSHDATA1 => {
89             code => "\x4c",
90             pushes => !!1,
91             runner => sub {
92             my ($runner, $bytes) = @_;
93              
94             push @{$runner->stack}, $bytes;
95             },
96             },
97             OP_PUSHDATA2 => {
98             code => "\x4d",
99             pushes => !!1,
100              
101             # see runner below
102             },
103             OP_PUSHDATA4 => {
104             code => "\x4e",
105             pushes => !!1,
106              
107             # see runner below
108             },
109             OP_1NEGATE => {
110             code => "\x4f",
111             runner => sub {
112             my $runner = shift;
113              
114             push @{$runner->stack}, $runner->from_int(-1);
115             },
116             },
117             OP_RESERVED => {
118             code => "\x50",
119             runner => sub { invalid_script },
120             },
121             OP_NOP => {
122             code => "\x61",
123             runner => sub {
124              
125             # does nothing
126             },
127             },
128             OP_VER => {
129             code => "\x62",
130             runner => sub { invalid_script },
131             },
132             OP_IF => {
133             code => "\x63",
134             runner => sub {
135             my ($runner, $else_pos, $endif_pos) = @_;
136             my $stack = $runner->stack;
137              
138             stack_error unless @$stack >= 1;
139             if ($runner->to_bool(pop @$stack)) {
140              
141             # continue execution
142             }
143             else {
144             if (defined $else_pos) {
145             $runner->_set_pos($else_pos);
146             }
147             else {
148             $runner->_set_pos($endif_pos);
149             }
150             }
151             },
152             },
153             OP_NOTIF => {
154             code => "\x64",
155              
156             # see runner below
157             },
158             OP_VERIF => {
159             code => "\x65",
160              
161             # NOTE: should also be invalid if the op is not run
162             runner => sub { invalid_script },
163             },
164             OP_VERNOTIF => {
165             code => "\x66",
166              
167             # NOTE: should also be invalid if the op is not run
168             runner => sub { invalid_script },
169             },
170             OP_ELSE => {
171             code => "\x67",
172              
173             # should only get called when IF branch ops are depleted
174             runner => sub {
175             my ($runner, $endif_pos) = @_;
176              
177             $runner->_set_pos($endif_pos);
178             },
179             },
180             OP_ENDIF => {
181             code => "\x68",
182              
183             # should only get called when IF or ELSE branch ops are depleted
184             runner => sub {
185              
186             # nothing to do here, will step to the next op
187             },
188             },
189             OP_VERIFY => {
190             code => "\x69",
191             runner => sub {
192             my $runner = shift;
193             my $stack = $runner->stack;
194              
195             invalid_script unless $runner->to_bool($stack->[-1]);
196              
197             # pop later so that problematic value can be seen on the stack
198             pop @$stack;
199             },
200             },
201             OP_RETURN => {
202             code => "\x6a",
203             runner => sub { invalid_script },
204             },
205             OP_TOALTSTACK => {
206             code => "\x6b",
207             runner => sub {
208             my $runner = shift;
209             my $stack = $runner->stack;
210              
211             stack_error unless @$stack >= 1;
212             push @{$runner->alt_stack}, pop @$stack;
213             },
214             },
215             OP_FROMALTSTACK => {
216             code => "\x6c",
217             runner => sub {
218             my $runner = shift;
219             my $alt = $runner->alt_stack;
220              
221             stack_error unless @$alt >= 1;
222             push @{$runner->stack}, pop @$alt;
223             },
224             },
225             OP_2DROP => {
226             code => "\x6d",
227             runner => sub {
228             my $runner = shift;
229             my $stack = $runner->stack;
230              
231             stack_error unless @$stack >= 2;
232             splice @$stack, -2, 2;
233             },
234             },
235             OP_2DUP => {
236             code => "\x6e",
237             runner => sub {
238             my $runner = shift;
239             my $stack = $runner->stack;
240              
241             stack_error unless @$stack >= 2;
242             push @$stack, @$stack[-2, -1];
243             },
244             },
245             OP_3DUP => {
246             code => "\x6f",
247             runner => sub {
248             my $runner = shift;
249             my $stack = $runner->stack;
250              
251             stack_error unless @$stack >= 3;
252             push @$stack, @$stack[-3, -2, -1];
253             },
254             },
255             OP_2OVER => {
256             code => "\x70",
257             runner => sub {
258             my $runner = shift;
259             my $stack = $runner->stack;
260              
261             stack_error unless @$stack >= 4;
262             push @$stack, @$stack[-4, -3];
263             },
264             },
265             OP_2ROT => {
266             code => "\x71",
267             runner => sub {
268             my $runner = shift;
269             my $stack = $runner->stack;
270              
271             stack_error unless @$stack >= 6;
272             push @$stack, splice @$stack, -6, 2;
273             },
274             },
275             OP_2SWAP => {
276             code => "\x72",
277             runner => sub {
278             my $runner = shift;
279             my $stack = $runner->stack;
280              
281             stack_error unless @$stack >= 4;
282             push @$stack, splice @$stack, -4, 2;
283             },
284             },
285             OP_IFDUP => {
286             code => "\x73",
287             runner => sub {
288             my $runner = shift;
289             my $stack = $runner->stack;
290              
291             stack_error unless @$stack >= 1;
292             if ($runner->to_bool($stack->[-1])) {
293             push @$stack, $stack->[-1];
294             }
295             },
296             },
297             OP_DEPTH => {
298             code => "\x74",
299             runner => sub {
300             my $runner = shift;
301             my $stack = $runner->stack;
302              
303             push @$stack, $runner->from_int(scalar @$stack);
304             },
305             },
306             OP_DROP => {
307             code => "\x75",
308             runner => sub {
309             my $runner = shift;
310             my $stack = $runner->stack;
311              
312             stack_error unless @$stack >= 1;
313             pop @$stack;
314             },
315             },
316             OP_DUP => {
317             code => "\x76",
318             runner => sub {
319             my $runner = shift;
320             my $stack = $runner->stack;
321              
322             stack_error unless @$stack >= 1;
323             push @$stack, $stack->[-1];
324             },
325             },
326             OP_NIP => {
327             code => "\x77",
328             runner => sub {
329             my $runner = shift;
330             my $stack = $runner->stack;
331              
332             stack_error unless @$stack >= 2;
333             splice @$stack, -2, 1;
334             },
335             },
336             OP_OVER => {
337             code => "\x78",
338             runner => sub {
339             my $runner = shift;
340             my $stack = $runner->stack;
341              
342             stack_error unless @$stack >= 2;
343             push @$stack, $stack->[-2];
344             },
345             },
346             OP_PICK => {
347             code => "\x79",
348             runner => sub {
349             my $runner = shift;
350             my $stack = $runner->stack;
351              
352             stack_error unless @$stack >= 2;
353              
354             my $n = $runner->to_int(pop @$stack);
355             stack_error if $n < 0 || $n >= @$stack;
356              
357             push @$stack, $stack->[-1 * ($n + 1)];
358             },
359             },
360             OP_ROLL => {
361             code => "\x7a",
362             runner => sub {
363             my $runner = shift;
364             my $stack = $runner->stack;
365              
366             stack_error unless @$stack >= 2;
367              
368             my $n = $runner->to_int(pop @$stack);
369             stack_error if $n < 0 || $n >= @$stack;
370              
371             push @$stack, splice @$stack, -1 * ($n + 1), 1;
372             },
373             },
374             OP_ROT => {
375             code => "\x7b",
376             runner => sub {
377             my $runner = shift;
378             my $stack = $runner->stack;
379              
380             stack_error unless @$stack >= 3;
381             push @$stack, splice @$stack, -3, 1;
382             },
383             },
384             OP_SWAP => {
385             code => "\x7c",
386             runner => sub {
387             my $runner = shift;
388             my $stack = $runner->stack;
389              
390             stack_error unless @$stack >= 2;
391             push @$stack, splice @$stack, -2, 1;
392             },
393             },
394             OP_TUCK => {
395             code => "\x7d",
396             runner => sub {
397             my $runner = shift;
398             my $stack = $runner->stack;
399              
400             stack_error unless @$stack >= 2;
401             splice @$stack, -2, 0, $stack->[-1];
402             },
403             },
404             OP_SIZE => {
405             code => "\x82",
406             runner => sub {
407             my $runner = shift;
408             my $stack = $runner->stack;
409              
410             stack_error unless @$stack >= 1;
411             push @$stack, $runner->from_int(length $stack->[-1]);
412             },
413             },
414             OP_EQUAL => {
415             code => "\x87",
416             runner => sub {
417             my $runner = shift;
418             my $stack = $runner->stack;
419              
420             stack_error unless @$stack >= 2;
421             push @$stack, $runner->from_bool(pop(@$stack) eq pop(@$stack));
422             },
423             },
424             OP_EQUALVERIFY => {
425             code => "\x88",
426              
427             # see runner below
428             },
429             OP_RESERVED1 => {
430             code => "\x89",
431             runner => sub { invalid_script },
432             },
433             OP_RESERVED2 => {
434             code => "\x8a",
435             runner => sub { invalid_script },
436             },
437             OP_1ADD => {
438             code => "\x8b",
439             runner => sub {
440             my $runner = shift;
441             my $stack = $runner->stack;
442              
443             stack_error unless @$stack >= 1;
444             push @$stack, $runner->from_int($runner->to_int(pop @$stack) + 1);
445             },
446             },
447             OP_1SUB => {
448             code => "\x8c",
449             runner => sub {
450             my $runner = shift;
451             my $stack = $runner->stack;
452              
453             stack_error unless @$stack >= 1;
454             push @$stack, $runner->from_int($runner->to_int(pop @$stack) - 1);
455             },
456             },
457             OP_NEGATE => {
458             code => "\x8f",
459             runner => sub {
460             my $runner = shift;
461             my $stack = $runner->stack;
462              
463             stack_error unless @$stack >= 1;
464             push @$stack, $runner->from_int($runner->to_int(pop @$stack) * -1);
465             },
466             },
467             OP_ABS => {
468             code => "\x90",
469             runner => sub {
470             my $runner = shift;
471             my $stack = $runner->stack;
472              
473             stack_error unless @$stack >= 1;
474             push @$stack, $runner->from_int(abs $runner->to_int(pop @$stack));
475             },
476             },
477             OP_NOT => {
478             code => "\x91",
479             runner => sub {
480             my $runner = shift;
481             my $stack = $runner->stack;
482              
483             stack_error unless @$stack >= 1;
484             push @$stack, $runner->from_bool($runner->to_int(pop @$stack) == 0);
485             },
486             },
487             OP_0NOTEQUAL => {
488             code => "\x92",
489             runner => sub {
490             my $runner = shift;
491             my $stack = $runner->stack;
492              
493             stack_error unless @$stack >= 1;
494             push @$stack, $runner->from_bool($runner->to_int(pop @$stack) != 0);
495             },
496             },
497             OP_ADD => {
498             code => "\x93",
499             runner => sub {
500             my $runner = shift;
501             my $stack = $runner->stack;
502              
503             stack_error unless @$stack >= 2;
504             push @$stack, $runner->from_int(
505             $runner->to_int(pop @$stack)
506             + $runner->to_int(pop @$stack)
507             );
508             },
509             },
510             OP_SUB => {
511             code => "\x94",
512             runner => sub {
513             my $runner = shift;
514             my $stack = $runner->stack;
515              
516             stack_error unless @$stack >= 2;
517             push @$stack, $runner->from_int(
518             -1 * $runner->to_int(pop @$stack)
519             + $runner->to_int(pop @$stack)
520             );
521             },
522             },
523             OP_BOOLAND => {
524             code => "\x9a",
525             runner => sub {
526             my $runner = shift;
527             my $stack = $runner->stack;
528              
529             stack_error unless @$stack >= 2;
530              
531             my $second = $runner->to_int(pop @$stack) != 0;
532             push @$stack, $runner->from_bool(
533             $runner->to_int(pop @$stack) != 0
534             && $second
535             );
536             },
537             },
538             OP_BOOLOR => {
539             code => "\x9b",
540             runner => sub {
541             my $runner = shift;
542             my $stack = $runner->stack;
543              
544             stack_error unless @$stack >= 2;
545              
546             my $second = $runner->to_int(pop @$stack) != 0;
547             push @$stack, $runner->from_bool(
548             $runner->to_int(pop @$stack) != 0
549             || $second
550             );
551             },
552             },
553             OP_NUMEQUAL => {
554             code => "\x9c",
555             runner => sub {
556             my $runner = shift;
557             my $stack = $runner->stack;
558              
559             stack_error unless @$stack >= 2;
560             push @$stack, $runner->from_bool(
561             $runner->to_int(pop @$stack)
562             == $runner->to_int(pop @$stack)
563             );
564             },
565             },
566             OP_NUMEQUALVERIFY => {
567             code => "\x9d",
568              
569             # see runner below
570             },
571             OP_NUMNOTEQUAL => {
572             code => "\x9e",
573             runner => sub {
574             my $runner = shift;
575             my $stack = $runner->stack;
576              
577             stack_error unless @$stack >= 2;
578             push @$stack, $runner->from_bool(
579             $runner->to_int(pop @$stack)
580             != $runner->to_int(pop @$stack)
581             );
582             },
583             },
584             OP_LESSTHAN => {
585             code => "\x9f",
586             runner => sub {
587             my $runner = shift;
588             my $stack = $runner->stack;
589              
590             stack_error unless @$stack >= 2;
591             push @$stack, $runner->from_bool(
592             $runner->to_int(pop @$stack)
593             > $runner->to_int(pop @$stack)
594             );
595             },
596             },
597             OP_GREATERTHAN => {
598             code => "\xa0",
599             runner => sub {
600             my $runner = shift;
601             my $stack = $runner->stack;
602              
603             stack_error unless @$stack >= 2;
604             push @$stack, $runner->from_bool(
605             $runner->to_int(pop @$stack)
606             < $runner->to_int(pop @$stack)
607             );
608             },
609             },
610             OP_LESSTHANOREQUAL => {
611             code => "\xa1",
612             runner => sub {
613             my $runner = shift;
614             my $stack = $runner->stack;
615              
616             stack_error unless @$stack >= 2;
617             push @$stack, $runner->from_bool(
618             $runner->to_int(pop @$stack)
619             >= $runner->to_int(pop @$stack)
620             );
621             },
622             },
623             OP_GREATERTHANOREQUAL => {
624             code => "\xa2",
625             runner => sub {
626             my $runner = shift;
627             my $stack = $runner->stack;
628              
629             stack_error unless @$stack >= 2;
630             push @$stack, $runner->from_bool(
631             $runner->to_int(pop @$stack)
632             <= $runner->to_int(pop @$stack)
633             );
634             },
635             },
636             OP_MIN => {
637             code => "\xa3",
638             runner => sub {
639             my $runner = shift;
640             my $stack = $runner->stack;
641              
642             stack_error unless @$stack >= 2;
643             my ($first, $second) = splice @$stack, -2, 2;
644             push @$stack, $runner->to_int($first) < $runner->to_int($second)
645             ? $first : $second;
646             },
647             },
648             OP_MAX => {
649             code => "\xa4",
650             runner => sub {
651             my $runner = shift;
652             my $stack = $runner->stack;
653              
654             stack_error unless @$stack >= 2;
655             my ($first, $second) = splice @$stack, -2, 2;
656             push @$stack, $runner->to_int($first) > $runner->to_int($second)
657             ? $first : $second;
658             },
659             },
660             OP_WITHIN => {
661             code => "\xa5",
662             runner => sub {
663             my $runner = shift;
664             my $stack = $runner->stack;
665              
666             stack_error unless @$stack >= 3;
667             my ($first, $second, $third) = map { $runner->to_int($_) } splice @$stack, -3, 3;
668             push @$stack, $runner->from_bool($first >= $second && $first < $third);
669             },
670             },
671             OP_RIPEMD160 => {
672             code => "\xa6",
673             runner => sub {
674             my $runner = shift;
675             my $stack = $runner->stack;
676              
677             stack_error unless @$stack >= 1;
678             push @$stack, ripemd160(pop @$stack);
679             },
680             },
681             OP_SHA1 => {
682             code => "\xa7",
683             runner => sub {
684             my $runner = shift;
685             my $stack = $runner->stack;
686              
687             stack_error unless @$stack >= 1;
688             push @$stack, sha1(pop @$stack);
689             },
690             },
691             OP_SHA256 => {
692             code => "\xa8",
693             runner => sub {
694             my $runner = shift;
695             my $stack = $runner->stack;
696              
697             stack_error unless @$stack >= 1;
698             push @$stack, sha256(pop @$stack);
699             },
700             },
701             OP_HASH160 => {
702             code => "\xa9",
703             runner => sub {
704             my $runner = shift;
705             my $stack = $runner->stack;
706              
707             stack_error unless @$stack >= 1;
708             push @$stack, hash160(pop @$stack);
709             },
710             },
711             OP_HASH256 => {
712             code => "\xaa",
713             runner => sub {
714             my $runner = shift;
715             my $stack = $runner->stack;
716              
717             stack_error unless @$stack >= 1;
718             push @$stack, hash256(pop @$stack);
719             },
720             },
721             OP_CODESEPARATOR => {
722             code => "\xab",
723             needs_transaction => !!1,
724              
725             runner => sub {
726             my $runner = shift;
727             $runner->_register_codeseparator;
728             },
729             },
730             OP_CHECKSIG => {
731             code => "\xac",
732             needs_transaction => !!1,
733              
734             runner => sub {
735             my $runner = shift;
736              
737             my $stack = $runner->stack;
738             stack_error unless @$stack >= 2;
739              
740             my $raw_pubkey = pop @$stack;
741             my $sig = pop @$stack;
742             my $hashtype = substr $sig, -1, 1, '';
743              
744             my $digest = $runner->transaction->get_digest($runner->subscript, unpack 'C', $hashtype);
745             my $pubkey = btc_pub->from_serialized($raw_pubkey);
746              
747             script_error('SegWit validation requires compressed public key')
748             if !$pubkey->compressed && $runner->transaction->is_native_segwit;
749              
750             my $result = $pubkey->verify_message($digest, $sig);
751             push @$stack, $runner->from_bool($result);
752             },
753             },
754             OP_CHECKSIGVERIFY => {
755             code => "\xad",
756             needs_transaction => !!1,
757              
758             # see runner below
759             },
760             OP_CHECKMULTISIG => {
761             code => "\xae",
762             needs_transaction => !!1,
763              
764             runner => sub {
765             my $runner = shift;
766              
767             my $stack = $runner->stack;
768             stack_error unless @$stack >= 1;
769              
770             my $pubkeys_num = $runner->to_int(pop @$stack);
771             stack_error unless $pubkeys_num > 0 && @$stack >= $pubkeys_num;
772             my @pubkeys = splice @$stack, -$pubkeys_num;
773              
774             script_error('SegWit validation requires all public keys to be compressed')
775             if $runner->transaction->is_native_segwit && grep { !get_public_key_compressed($_) } @pubkeys;
776              
777             my $signatures_num = $runner->to_int(pop @$stack);
778             stack_error unless $signatures_num > 0 && @$stack >= $signatures_num;
779             my @signatures = splice @$stack, -$signatures_num;
780              
781             my $subscript = $runner->subscript;
782             my $found;
783             while (my $sig = shift @signatures) {
784             my $hashtype = substr $sig, -1, 1, '';
785              
786             my $digest = $runner->transaction->get_digest($subscript, unpack 'C', $hashtype);
787             $found = !!0;
788             while (my $raw_pubkey = shift @pubkeys) {
789             my $pubkey = btc_pub->from_serialized($raw_pubkey);
790             $found = $pubkey->verify_message($digest, $sig);
791             last if $found;
792             }
793              
794             last if !$found;
795             }
796              
797             # Remove extra unused value from the stack
798             my $unused = pop @$stack;
799             script_error('OP_CHECKMULTISIG dummy argument must be empty')
800             if length $unused;
801              
802             my $result = $found && !@signatures;
803             push @$stack, $runner->from_bool($result);
804             },
805             },
806             OP_CHECKMULTISIGVERIFY => {
807             code => "\xaf",
808             needs_transaction => !!1,
809              
810             # see runner below
811             },
812             OP_NOP1 => {
813             code => "\xb0",
814             runner => sub { 'NOP' },
815             },
816             OP_CHECKLOCKTIMEVERIFY => {
817             code => "\xb1",
818             needs_transaction => !!1,
819              
820             runner => sub {
821             my $runner = shift;
822             my $transaction = $runner->transaction;
823              
824             my $stack = $runner->stack;
825             stack_error unless @$stack >= 1;
826              
827             my $c1 = $runner->to_int($stack->[-1]);
828             my $c2 = $runner->transaction->locktime;
829              
830             invalid_script
831             if $c1 < 0;
832              
833             my $c1_is_height = $c1 < Bitcoin::Crypto::Constants::locktime_height_threshold;
834             my $c2_is_height = $c2 < Bitcoin::Crypto::Constants::locktime_height_threshold;
835              
836             invalid_script
837             if !!$c1_is_height ne !!$c2_is_height;
838              
839             invalid_script
840             if $c1 > $c2;
841              
842             my $input = $transaction->inputs->[$transaction->input_index];
843             invalid_script
844             if $input->sequence_no == Bitcoin::Crypto::Constants::max_sequence_no;
845              
846             pop @$stack;
847             },
848             },
849             OP_CHECKSEQUENCEVERIFY => {
850             code => "\xb2",
851             needs_transaction => !!1,
852              
853             runner => sub {
854             my $runner = shift;
855             my $transaction = $runner->transaction;
856              
857             my $stack = $runner->stack;
858             stack_error unless @$stack >= 1;
859              
860             my $c1 = $runner->to_int($stack->[-1]);
861              
862             invalid_script
863             if $c1 < 0;
864              
865             if (!($c1 & (1 << 31))) {
866             invalid_script
867             if $transaction->version < 2;
868              
869             my $c2 = $transaction->this_input->sequence_no;
870              
871             invalid_script
872             if $c2 & (1 << 31);
873              
874             my $c1_is_time = $c1 & (1 << 22);
875             my $c2_is_time = $c2 & (1 << 22);
876              
877             invalid_script
878             if !!$c1_is_time ne !!$c2_is_time;
879              
880             invalid_script
881             if ($c1 & 0x0000ffff) > ($c2 & 0x0000ffff);
882             }
883              
884             pop @$stack;
885             },
886             },
887             OP_NOP4 => {
888             code => "\xb3",
889             runner => sub { 'NOP' },
890             },
891             OP_NOP5 => {
892             code => "\xb4",
893             runner => sub { 'NOP' },
894             },
895             OP_NOP6 => {
896             code => "\xb5",
897             runner => sub { 'NOP' },
898             },
899             OP_NOP7 => {
900             code => "\xb6",
901             runner => sub { 'NOP' },
902             },
903             OP_NOP8 => {
904             code => "\xb7",
905             runner => sub { 'NOP' },
906             },
907             OP_NOP9 => {
908             code => "\xb8",
909             runner => sub { 'NOP' },
910             },
911             OP_NOP10 => {
912             code => "\xb9",
913             runner => sub { 'NOP' },
914             },
915             );
916              
917             for my $num (1 .. 16) {
918             $opcodes{"OP_$num"} = {
919             code => chr(0x50 + $num),
920             pushes => !!1,
921             runner => sub {
922             my $runner = shift;
923             push @{$runner->stack}, $runner->from_int($num);
924             }
925             };
926             }
927              
928             # runners for these are the same, since the script is complied
929             $opcodes{OP_PUSHDATA4}{runner} =
930             $opcodes{OP_PUSHDATA1}{runner};
931              
932             # runners for these are the same, since the script is complied
933             $opcodes{OP_PUSHDATA2}{runner} =
934             $opcodes{OP_PUSHDATA1}{runner};
935              
936             $opcodes{OP_NOTIF}{runner} = sub {
937             $opcodes{OP_NOT}{runner}->(@_);
938             $opcodes{OP_IF}{runner}->(@_);
939             };
940              
941             $opcodes{OP_EQUALVERIFY}{runner} = sub {
942             $opcodes{OP_EQUAL}{runner}->(@_);
943             $opcodes{OP_VERIFY}{runner}->(@_);
944             };
945              
946             $opcodes{OP_NUMEQUALVERIFY}{runner} = sub {
947             $opcodes{OP_NUMEQUAL}{runner}->(@_);
948             $opcodes{OP_VERIFY}{runner}->(@_);
949             };
950              
951             $opcodes{OP_CHECKSIGVERIFY}{runner} = sub {
952             $opcodes{OP_CHECKSIG}{runner}->(@_);
953             $opcodes{OP_VERIFY}{runner}->(@_);
954             };
955              
956             $opcodes{OP_CHECKMULTISIGVERIFY}{runner} = sub {
957             $opcodes{OP_CHECKMULTISIG}{runner}->(@_);
958             $opcodes{OP_VERIFY}{runner}->(@_);
959             };
960              
961             my %opcodes_reverse = map { $opcodes{$_}{code}, $_ } keys %opcodes;
962              
963             # aliases are added after setting up reverse mapping to end up with
964             # deterministic results of get_opcode_by_code. This means opcodes below will
965             # never be returned by that method.
966             $opcodes{OP_FALSE} = $opcodes{OP_0};
967             $opcodes{OP_TRUE} = $opcodes{OP_1};
968              
969             %opcodes = map { $_, __PACKAGE__->new(name => $_, %{$opcodes{$_}}) } keys %opcodes;
970              
971             sub get_opcode_by_code
972             {
973 1475     1475 1 2943 my ($self, $code) = @_;
974              
975 1475 50       3082 Bitcoin::Crypto::Exception::ScriptOpcode->raise(
976             'undefined opcode code argument'
977             ) unless defined $code;
978              
979             Bitcoin::Crypto::Exception::ScriptOpcode->raise(
980             "unknown opcode code " . unpack 'H*', $code
981 1475 100       5711 ) unless exists $opcodes_reverse{$code};
982              
983 1036         2671 return $opcodes{$opcodes_reverse{$code}};
984             }
985              
986             sub get_opcode_by_name
987             {
988 1807     1807 1 3519 my ($self, $opcode) = @_;
989              
990 1807 50       3629 Bitcoin::Crypto::Exception::ScriptOpcode->raise(
991             'undefined opcode name argument'
992             ) unless defined $opcode;
993              
994             Bitcoin::Crypto::Exception::ScriptOpcode->raise(
995             "unknown opcode $opcode"
996 1807 50       4296 ) unless exists $opcodes{$opcode};
997              
998 1807         4263 return $opcodes{$opcode};
999             }
1000              
1001             1;
1002              
1003             __END__
1004              
1005             =head1 NAME
1006              
1007             Bitcoin::Crypto::Script::Opcode - Bitcoin Script opcode
1008              
1009             =head1 SYNOPSIS
1010              
1011             use Bitcoin::Crypto::Script::Opcode;
1012              
1013             my $opcode1 = Bitcoin::Crypto::Script::Opcode->get_opcode_by_code("\x00");
1014             my $opcode2 = Bitcoin::Crypto::Script::Opcode->get_opcode_by_name('OP_1');
1015              
1016             print $opcode1->name; # 'OP_0'
1017             print $opcode1->code; # "\x00"
1018             print 'implemented' if $opcode1->implemented;
1019              
1020             =head1 DESCRIPTION
1021              
1022             This is both a library of opcodes and a small struct-like class for opcodes.
1023              
1024             =head1 INTERFACE
1025              
1026             =head2 Class (static) methods
1027              
1028             These methods are used to find an opcode.
1029              
1030             =head3 get_opcode_by_name
1031              
1032             my $object = Bitcoin::Crypto::Script::Opcode->get_opcode_by_name($name);
1033              
1034             Finds an opcode by its name (C<OP_XXX>) and returns an object instance.
1035              
1036             If opcode was not found an exception is raised
1037             (C<Bitcoin::Crypto::Exception::ScriptOpcode>).
1038              
1039             =head3 get_opcode_by_code
1040              
1041             my $object = Bitcoin::Crypto::Script::Opcode->get_opcode_by_code($bytestr);
1042              
1043             Finds an opcode by its code (bytestring of length 1) and returns an object
1044             instance.
1045              
1046             If opcode was not found an exception is raised (C<Bitcoin::Crypto::Exception::ScriptOpcode>).
1047              
1048             =head2 Attributes
1049              
1050             =head3 name
1051              
1052             The name of the opcode (C<OP_XXX>).
1053              
1054             =head3 code
1055              
1056             The code of the opcode - a bytestring of length 1.
1057              
1058             =head3 runner
1059              
1060             A coderef which can be used to execute this opcode.
1061              
1062             =head2 Methods
1063              
1064             =head3 execute
1065              
1066             Executes this opcode. Internal use only.
1067              
1068             =head1 SEE ALSO
1069              
1070             L<Bitcoin::Crypto::Script>
1071