Line data Source code
1 : import 'dart:typed_data';
2 :
3 : import 'package:walletkit_dart/src/crypto/utxo/entities/op_codes.dart';
4 : import 'package:walletkit_dart/src/domain/constants.dart';
5 : import 'package:walletkit_dart/src/utils/int.dart';
6 : import 'package:walletkit_dart/src/utils/var_uint.dart';
7 :
8 : class Script {
9 : final Uint8List bytes;
10 :
11 2 : const Script(this.bytes);
12 :
13 2 : List<ScriptChunk> get chunks {
14 2 : List<ScriptChunk> chunks = [];
15 : int offset = 0;
16 :
17 6 : while (offset < bytes.length) {
18 4 : int opcode = bytes[offset];
19 2 : offset += 1;
20 : int? dataToRead;
21 :
22 4 : if (opcode >= 0 && opcode <= OP_PUSHDATA1) {
23 : // The opcode value itself is length of data
24 : dataToRead = opcode;
25 2 : } else if (opcode == OP_PUSHDATA1) {
26 : // Next byte is length of data
27 0 : if (bytes.length - offset < 1)
28 0 : throw Exception('Unexpected end of script');
29 0 : dataToRead = bytes.bytes.readUint8(offset).$1;
30 0 : offset += 1;
31 2 : } else if (opcode == OP_PUSHDATA2) {
32 : // Next two bytes are length of data
33 0 : if (bytes.length - offset < 2)
34 0 : throw Exception('Unexpected end of script');
35 0 : dataToRead = bytes.bytes.readUint16(offset).$1;
36 0 : offset += 2;
37 2 : } else if (opcode == OP_PUSHDATA4) {
38 : // Next four bytes are length of data
39 0 : if (bytes.length - offset < 4)
40 0 : throw Exception('Unexpected end of script');
41 0 : dataToRead = bytes.bytes.readUint32(offset).$1;
42 0 : offset += 4;
43 : }
44 :
45 : final ScriptChunk chunk;
46 : if (dataToRead == null) {
47 2 : chunk = ScriptChunk(opcode, null);
48 : } else {
49 8 : if (dataToRead > bytes.length - offset)
50 0 : throw Exception(
51 0 : 'Push of data element that is larger than remaining data: $dataToRead vs ${bytes.length - offset} ');
52 6 : final data = bytes.sublist(offset, offset + dataToRead);
53 2 : chunk = ScriptChunk(opcode, data);
54 2 : offset += dataToRead;
55 : }
56 :
57 2 : chunks.add(chunk);
58 : }
59 6 : if (offset != bytes.length) throw Exception('Script parsing error');
60 : return chunks;
61 : }
62 : }
63 :
64 : class ScriptChunk {
65 : final int opcode;
66 : final Uint8List? data;
67 :
68 2 : const ScriptChunk(this.opcode, this.data);
69 : }
70 :
71 2 : BigInt getScriptWeight(Uint8List scriptBytes) {
72 4 : final scriptChunks = Script(scriptBytes).chunks;
73 :
74 2 : BigInt w = BigInt.zero;
75 : bool dataMode = false;
76 2 : int lastOpcode = -1; // OP_INVALIDOPCODE
77 4 : for (ScriptChunk scriptChunk in scriptChunks) {
78 10 : if (scriptChunk.data != null) w += scriptChunk.data!.length.toBI;
79 :
80 : if (dataMode) {
81 0 : w += 5.toBI;
82 : continue;
83 : }
84 :
85 2 : final opcode = scriptChunk.opcode;
86 :
87 : switch (opcode) {
88 2 : case OP_RETURN:
89 : dataMode = true;
90 0 : w += 5.toBI;
91 : break;
92 2 : case OP_RIPEMD160:
93 2 : case OP_SHA1:
94 2 : case OP_SHA256:
95 2 : case OP_HASH160:
96 2 : case OP_HASH256:
97 4 : w += 10.toBI;
98 : break;
99 2 : case OP_CODESEPARATOR:
100 0 : w += 10.toBI;
101 : break;
102 2 : case OP_CHECKSIG:
103 2 : case OP_CHECKSIGVERIFY:
104 4 : w += 100.toBI;
105 : break;
106 2 : case OP_CHECKMULTISIG:
107 2 : case OP_CHECKMULTISIGVERIFY:
108 0 : if (lastOpcode >= OP_1 && lastOpcode <= OP_16)
109 0 : w += (100 * decodeOP_N(lastOpcode)).toBI;
110 : else
111 0 : w += (100 * MAX_PUBKEYS_PER_MULTISIG).toBI;
112 : break;
113 2 : case OP_RESERVED1:
114 2 : case OP_RESERVED2:
115 2 : case OP_NOP1:
116 2 : case OP_NOP2:
117 2 : case OP_NOP3:
118 2 : case OP_NOP4:
119 2 : case OP_NOP5:
120 2 : case OP_NOP6:
121 2 : case OP_NOP7:
122 2 : case OP_NOP8:
123 2 : case OP_NOP9:
124 2 : case OP_NOP10:
125 0 : w += 10000.toBI;
126 : break;
127 : // case OP_INVALIDOPCODE:
128 : // w += 100000.toBI;
129 : // break;
130 :
131 : default:
132 4 : w += 5.toBI;
133 : break;
134 : }
135 : lastOpcode = opcode;
136 : }
137 :
138 0 : if (dataMode) w *= 20.toBI;
139 :
140 : return w;
141 : }
142 :
143 0 : int decodeOP_N(int opcode) {
144 : // Subtracting opcode by (OpCode.OP_1 - 1) to get the numeric value
145 0 : return opcode - (OPCODE.OP_1.hex - 1);
146 : }
|