Generic class was a bit excessive for our purposes
[NovacoinLibrary.git] / Novacoin / ScriptCode.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Novacoin
7 {
8     /// <summary>
9     /// Script opcodes
10     /// </summary>
11     public enum opcodetype
12     {
13         // push value
14         OP_0 = 0x00,
15         OP_FALSE = OP_0,
16         OP_PUSHDATA1 = 0x4c,
17         OP_PUSHDATA2 = 0x4d,
18         OP_PUSHDATA4 = 0x4e,
19         OP_1NEGATE = 0x4f,
20         OP_RESERVED = 0x50,
21         OP_1 = 0x51,
22         OP_TRUE = OP_1,
23         OP_2 = 0x52,
24         OP_3 = 0x53,
25         OP_4 = 0x54,
26         OP_5 = 0x55,
27         OP_6 = 0x56,
28         OP_7 = 0x57,
29         OP_8 = 0x58,
30         OP_9 = 0x59,
31         OP_10 = 0x5a,
32         OP_11 = 0x5b,
33         OP_12 = 0x5c,
34         OP_13 = 0x5d,
35         OP_14 = 0x5e,
36         OP_15 = 0x5f,
37         OP_16 = 0x60,
38
39         // control
40         OP_NOP = 0x61,
41         OP_VER = 0x62,
42         OP_IF = 0x63,
43         OP_NOTIF = 0x64,
44         OP_VERIF = 0x65,
45         OP_VERNOTIF = 0x66,
46         OP_ELSE = 0x67,
47         OP_ENDIF = 0x68,
48         OP_VERIFY = 0x69,
49         OP_RETURN = 0x6a,
50
51         // stack ops
52         OP_TOALTSTACK = 0x6b,
53         OP_FROMALTSTACK = 0x6c,
54         OP_2DROP = 0x6d,
55         OP_2DUP = 0x6e,
56         OP_3DUP = 0x6f,
57         OP_2OVER = 0x70,
58         OP_2ROT = 0x71,
59         OP_2SWAP = 0x72,
60         OP_IFDUP = 0x73,
61         OP_DEPTH = 0x74,
62         OP_DROP = 0x75,
63         OP_DUP = 0x76,
64         OP_NIP = 0x77,
65         OP_OVER = 0x78,
66         OP_PICK = 0x79,
67         OP_ROLL = 0x7a,
68         OP_ROT = 0x7b,
69         OP_SWAP = 0x7c,
70         OP_TUCK = 0x7d,
71
72         // splice ops
73         OP_CAT = 0x7e,
74         OP_SUBSTR = 0x7f,
75         OP_LEFT = 0x80,
76         OP_RIGHT = 0x81,
77         OP_SIZE = 0x82,
78
79         // bit logic
80         OP_INVERT = 0x83,
81         OP_AND = 0x84,
82         OP_OR = 0x85,
83         OP_XOR = 0x86,
84         OP_EQUAL = 0x87,
85         OP_EQUALVERIFY = 0x88,
86         OP_RESERVED1 = 0x89,
87         OP_RESERVED2 = 0x8a,
88
89         // numeric
90         OP_1ADD = 0x8b,
91         OP_1SUB = 0x8c,
92         OP_2MUL = 0x8d,
93         OP_2DIV = 0x8e,
94         OP_NEGATE = 0x8f,
95         OP_ABS = 0x90,
96         OP_NOT = 0x91,
97         OP_0NOTEQUAL = 0x92,
98
99         OP_ADD = 0x93,
100         OP_SUB = 0x94,
101         OP_MUL = 0x95,
102         OP_DIV = 0x96,
103         OP_MOD = 0x97,
104         OP_LSHIFT = 0x98,
105         OP_RSHIFT = 0x99,
106
107         OP_BOOLAND = 0x9a,
108         OP_BOOLOR = 0x9b,
109         OP_NUMEQUAL = 0x9c,
110         OP_NUMEQUALVERIFY = 0x9d,
111         OP_NUMNOTEQUAL = 0x9e,
112         OP_LESSTHAN = 0x9f,
113         OP_GREATERTHAN = 0xa0,
114         OP_LESSTHANOREQUAL = 0xa1,
115         OP_GREATERTHANOREQUAL = 0xa2,
116         OP_MIN = 0xa3,
117         OP_MAX = 0xa4,
118
119         OP_WITHIN = 0xa5,
120
121         // crypto
122         OP_RIPEMD160 = 0xa6,
123         OP_SHA1 = 0xa7,
124         OP_SHA256 = 0xa8,
125         OP_HASH160 = 0xa9,
126         OP_HASH256 = 0xaa,
127         OP_CODESEPARATOR = 0xab,
128         OP_CHECKSIG = 0xac,
129         OP_CHECKSIGVERIFY = 0xad,
130         OP_CHECKMULTISIG = 0xae,
131         OP_CHECKMULTISIGVERIFY = 0xaf,
132
133         // expansion
134         OP_NOP1 = 0xb0,
135         OP_NOP2 = 0xb1,
136         OP_NOP3 = 0xb2,
137         OP_NOP4 = 0xb3,
138         OP_NOP5 = 0xb4,
139         OP_NOP6 = 0xb5,
140         OP_NOP7 = 0xb6,
141         OP_NOP8 = 0xb7,
142         OP_NOP9 = 0xb8,
143         OP_NOP10 = 0xb9,
144
145         // template matching params
146         OP_SMALLDATA = 0xf9,
147         OP_SMALLINTEGER = 0xfa,
148         OP_PUBKEYS = 0xfb,
149         OP_PUBKEYHASH = 0xfd,
150         OP_PUBKEY = 0xfe,
151
152         OP_INVALIDOPCODE = 0xff,
153     };
154
155     /// <summary>
156     /// Transaction output types.
157     /// </summary>
158     public enum txnouttype
159     {
160         TX_NONSTANDARD,
161
162         // 'standard' transaction types:
163         TX_PUBKEY,
164         TX_PUBKEYHASH,
165         TX_SCRIPTHASH,
166         TX_MULTISIG,
167         TX_NULL_DATA,
168     };
169
170     /// <summary>
171     /// Signature hash types/flags
172     /// </summary>
173     public enum sigflag
174     {
175         SIGHASH_ALL = 1,
176         SIGHASH_NONE = 2,
177         SIGHASH_SINGLE = 3,
178         SIGHASH_ANYONECANPAY = 0x80,
179     };
180
181     public static class ScriptCode
182     {
183         public static string GetTxnOutputType(txnouttype t)
184         {
185             switch (t)
186             {
187                 case txnouttype.TX_NONSTANDARD: return "nonstandard";
188                 case txnouttype.TX_PUBKEY: return "pubkey";
189                 case txnouttype.TX_PUBKEYHASH: return "pubkeyhash";
190                 case txnouttype.TX_SCRIPTHASH: return "scripthash";
191                 case txnouttype.TX_MULTISIG: return "multisig";
192                 case txnouttype.TX_NULL_DATA: return "nulldata";
193             }
194             return string.Empty;
195         }
196
197         /// <summary>
198         /// Get the name of supplied opcode
199         /// </summary>
200         /// <param name="opcode">Opcode</param>
201         /// <returns>Opcode name</returns>
202         public static string GetOpName(opcodetype opcode)
203         {
204             switch (opcode)
205             {
206                 // push value
207                 case opcodetype.OP_0:
208                     return "0";
209                 case opcodetype.OP_PUSHDATA1:
210                     return "OP_PUSHDATA1";
211                 case opcodetype.OP_PUSHDATA2:
212                     return "OP_PUSHDATA2";
213                 case opcodetype.OP_PUSHDATA4:
214                     return "OP_PUSHDATA4";
215                 case opcodetype.OP_1NEGATE:
216                     return "-1";
217                 case opcodetype.OP_RESERVED:
218                     return "OP_RESERVED";
219                 case opcodetype.OP_1:
220                     return "1";
221                 case opcodetype.OP_2:
222                     return "2";
223                 case opcodetype.OP_3:
224                     return "3";
225                 case opcodetype.OP_4:
226                     return "4";
227                 case opcodetype.OP_5:
228                     return "5";
229                 case opcodetype.OP_6:
230                     return "6";
231                 case opcodetype.OP_7:
232                     return "7";
233                 case opcodetype.OP_8:
234                     return "8";
235                 case opcodetype.OP_9:
236                     return "9";
237                 case opcodetype.OP_10:
238                     return "10";
239                 case opcodetype.OP_11:
240                     return "11";
241                 case opcodetype.OP_12:
242                     return "12";
243                 case opcodetype.OP_13:
244                     return "13";
245                 case opcodetype.OP_14:
246                     return "14";
247                 case opcodetype.OP_15:
248                     return "15";
249                 case opcodetype.OP_16:
250                     return "16";
251
252                 // control
253                 case opcodetype.OP_NOP:
254                     return "OP_NOP";
255                 case opcodetype.OP_VER:
256                     return "OP_VER";
257                 case opcodetype.OP_IF:
258                     return "OP_IF";
259                 case opcodetype.OP_NOTIF:
260                     return "OP_NOTIF";
261                 case opcodetype.OP_VERIF:
262                     return "OP_VERIF";
263                 case opcodetype.OP_VERNOTIF:
264                     return "OP_VERNOTIF";
265                 case opcodetype.OP_ELSE:
266                     return "OP_ELSE";
267                 case opcodetype.OP_ENDIF:
268                     return "OP_ENDIF";
269                 case opcodetype.OP_VERIFY:
270                     return "OP_VERIFY";
271                 case opcodetype.OP_RETURN:
272                     return "OP_RETURN";
273
274                 // stack ops
275                 case opcodetype.OP_TOALTSTACK:
276                     return "OP_TOALTSTACK";
277                 case opcodetype.OP_FROMALTSTACK:
278                     return "OP_FROMALTSTACK";
279                 case opcodetype.OP_2DROP:
280                     return "OP_2DROP";
281                 case opcodetype.OP_2DUP:
282                     return "OP_2DUP";
283                 case opcodetype.OP_3DUP:
284                     return "OP_3DUP";
285                 case opcodetype.OP_2OVER:
286                     return "OP_2OVER";
287                 case opcodetype.OP_2ROT:
288                     return "OP_2ROT";
289                 case opcodetype.OP_2SWAP:
290                     return "OP_2SWAP";
291                 case opcodetype.OP_IFDUP:
292                     return "OP_IFDUP";
293                 case opcodetype.OP_DEPTH:
294                     return "OP_DEPTH";
295                 case opcodetype.OP_DROP:
296                     return "OP_DROP";
297                 case opcodetype.OP_DUP:
298                     return "OP_DUP";
299                 case opcodetype.OP_NIP:
300                     return "OP_NIP";
301                 case opcodetype.OP_OVER:
302                     return "OP_OVER";
303                 case opcodetype.OP_PICK:
304                     return "OP_PICK";
305                 case opcodetype.OP_ROLL:
306                     return "OP_ROLL";
307                 case opcodetype.OP_ROT:
308                     return "OP_ROT";
309                 case opcodetype.OP_SWAP:
310                     return "OP_SWAP";
311                 case opcodetype.OP_TUCK:
312                     return "OP_TUCK";
313
314                 // splice ops
315                 case opcodetype.OP_CAT:
316                     return "OP_CAT";
317                 case opcodetype.OP_SUBSTR:
318                     return "OP_SUBSTR";
319                 case opcodetype.OP_LEFT:
320                     return "OP_LEFT";
321                 case opcodetype.OP_RIGHT:
322                     return "OP_RIGHT";
323                 case opcodetype.OP_SIZE:
324                     return "OP_SIZE";
325
326                 // bit logic
327                 case opcodetype.OP_INVERT:
328                     return "OP_INVERT";
329                 case opcodetype.OP_AND:
330                     return "OP_AND";
331                 case opcodetype.OP_OR:
332                     return "OP_OR";
333                 case opcodetype.OP_XOR:
334                     return "OP_XOR";
335                 case opcodetype.OP_EQUAL:
336                     return "OP_EQUAL";
337                 case opcodetype.OP_EQUALVERIFY:
338                     return "OP_EQUALVERIFY";
339                 case opcodetype.OP_RESERVED1:
340                     return "OP_RESERVED1";
341                 case opcodetype.OP_RESERVED2:
342                     return "OP_RESERVED2";
343
344                 // numeric
345                 case opcodetype.OP_1ADD:
346                     return "OP_1ADD";
347                 case opcodetype.OP_1SUB:
348                     return "OP_1SUB";
349                 case opcodetype.OP_2MUL:
350                     return "OP_2MUL";
351                 case opcodetype.OP_2DIV:
352                     return "OP_2DIV";
353                 case opcodetype.OP_NEGATE:
354                     return "OP_NEGATE";
355                 case opcodetype.OP_ABS:
356                     return "OP_ABS";
357                 case opcodetype.OP_NOT:
358                     return "OP_NOT";
359                 case opcodetype.OP_0NOTEQUAL:
360                     return "OP_0NOTEQUAL";
361                 case opcodetype.OP_ADD:
362                     return "OP_ADD";
363                 case opcodetype.OP_SUB:
364                     return "OP_SUB";
365                 case opcodetype.OP_MUL:
366                     return "OP_MUL";
367                 case opcodetype.OP_DIV:
368                     return "OP_DIV";
369                 case opcodetype.OP_MOD:
370                     return "OP_MOD";
371                 case opcodetype.OP_LSHIFT:
372                     return "OP_LSHIFT";
373                 case opcodetype.OP_RSHIFT:
374                     return "OP_RSHIFT";
375                 case opcodetype.OP_BOOLAND:
376                     return "OP_BOOLAND";
377                 case opcodetype.OP_BOOLOR:
378                     return "OP_BOOLOR";
379                 case opcodetype.OP_NUMEQUAL:
380                     return "OP_NUMEQUAL";
381                 case opcodetype.OP_NUMEQUALVERIFY:
382                     return "OP_NUMEQUALVERIFY";
383                 case opcodetype.OP_NUMNOTEQUAL:
384                     return "OP_NUMNOTEQUAL";
385                 case opcodetype.OP_LESSTHAN:
386                     return "OP_LESSTHAN";
387                 case opcodetype.OP_GREATERTHAN:
388                     return "OP_GREATERTHAN";
389                 case opcodetype.OP_LESSTHANOREQUAL:
390                     return "OP_LESSTHANOREQUAL";
391                 case opcodetype.OP_GREATERTHANOREQUAL:
392                     return "OP_GREATERTHANOREQUAL";
393                 case opcodetype.OP_MIN:
394                     return "OP_MIN";
395                 case opcodetype.OP_MAX:
396                     return "OP_MAX";
397                 case opcodetype.OP_WITHIN:
398                     return "OP_WITHIN";
399
400                 // crypto
401                 case opcodetype.OP_RIPEMD160:
402                     return "OP_RIPEMD160";
403                 case opcodetype.OP_SHA1:
404                     return "OP_SHA1";
405                 case opcodetype.OP_SHA256:
406                     return "OP_SHA256";
407                 case opcodetype.OP_HASH160:
408                     return "OP_HASH160";
409                 case opcodetype.OP_HASH256:
410                     return "OP_HASH256";
411                 case opcodetype.OP_CODESEPARATOR:
412                     return "OP_CODESEPARATOR";
413                 case opcodetype.OP_CHECKSIG:
414                     return "OP_CHECKSIG";
415                 case opcodetype.OP_CHECKSIGVERIFY:
416                     return "OP_CHECKSIGVERIFY";
417                 case opcodetype.OP_CHECKMULTISIG:
418                     return "OP_CHECKMULTISIG";
419                 case opcodetype.OP_CHECKMULTISIGVERIFY:
420                     return "OP_CHECKMULTISIGVERIFY";
421
422                 // expansion
423                 case opcodetype.OP_NOP1:
424                     return "OP_NOP1";
425                 case opcodetype.OP_NOP2:
426                     return "OP_NOP2";
427                 case opcodetype.OP_NOP3:
428                     return "OP_NOP3";
429                 case opcodetype.OP_NOP4:
430                     return "OP_NOP4";
431                 case opcodetype.OP_NOP5:
432                     return "OP_NOP5";
433                 case opcodetype.OP_NOP6:
434                     return "OP_NOP6";
435                 case opcodetype.OP_NOP7:
436                     return "OP_NOP7";
437                 case opcodetype.OP_NOP8:
438                     return "OP_NOP8";
439                 case opcodetype.OP_NOP9:
440                     return "OP_NOP9";
441                 case opcodetype.OP_NOP10:
442                     return "OP_NOP10";
443
444                 // template matching params
445                 case opcodetype.OP_PUBKEYHASH:
446                     return "OP_PUBKEYHASH";
447                 case opcodetype.OP_PUBKEY:
448                     return "OP_PUBKEY";
449                 case opcodetype.OP_SMALLDATA:
450                     return "OP_SMALLDATA";
451
452                 case opcodetype.OP_INVALIDOPCODE:
453                     return "OP_INVALIDOPCODE";
454                 default:
455                     return "OP_UNKNOWN";
456             }
457         }
458
459         /// <summary>
460         /// Get next opcode from passed list of bytes and extract push arguments if there are some.
461         /// </summary>
462         /// <param name="codeBytes">ByteQueue reference.</param>
463         /// <param name="opcodeRet">Found opcode.</param>
464         /// <param name="bytesRet">IEnumerable out param which is used to get the push arguments.</param>
465         /// <returns>Result of operation</returns>
466         public static bool GetOp(ref ByteQueue codeBytes, out opcodetype opcodeRet, out IEnumerable<byte> bytesRet)
467         {
468             bytesRet = new List<byte>();
469             opcodeRet = opcodetype.OP_INVALIDOPCODE;
470
471             opcodetype opcode;
472
473             try
474             {
475                 // Read instruction
476                 opcode = (opcodetype)codeBytes.Get();
477             }
478             catch (WrappedListException)
479             {
480                 // No instruction found there
481                 return false;
482             }
483
484             // Immediate operand
485             if (opcode <= opcodetype.OP_PUSHDATA4)
486             {
487                 byte[] szBytes = new byte[4] { 0, 0, 0, 0 }; // Zero length
488
489                 try
490                 {
491                     if (opcode < opcodetype.OP_PUSHDATA1)
492                     {
493                         // Zero value opcodes (OP_0, OP_FALSE)
494                         szBytes[3] = (byte)opcode;
495                     }
496                     else if (opcode == opcodetype.OP_PUSHDATA1)
497                     {
498                         // The next byte contains the number of bytes to be pushed onto the stack, 
499                         //    i.e. you have something like OP_PUSHDATA1 0x01 [0x5a]
500                         szBytes[3] = (byte)codeBytes.Get();
501                     }
502                     else if (opcode == opcodetype.OP_PUSHDATA2)
503                     {
504                         // The next two bytes contain the number of bytes to be pushed onto the stack,
505                         //    i.e. now your operation will seem like this: OP_PUSHDATA2 0x00 0x01 [0x5a]
506                         codeBytes.Get(2).CopyTo(szBytes, 2);
507                     }
508                     else if (opcode == opcodetype.OP_PUSHDATA4)
509                     {
510                         // The next four bytes contain the number of bytes to be pushed onto the stack,
511                         //   OP_PUSHDATA4 0x00 0x00 0x00 0x01 [0x5a]
512                         szBytes = codeBytes.Get(4);
513                     }
514                 }
515                 catch (WrappedListException)
516                 {
517                     // Unable to read operand length
518                     return false;
519                 }
520
521                 int nSize = (int)Interop.BEBytesToUInt32(szBytes);
522
523                 if (nSize > 0)
524                 {
525                     // If nSize is greater than zero then there is some data available
526                     try
527                     {
528                         // Read found number of bytes into list of OP_PUSHDATAn arguments.
529                         bytesRet = codeBytes.GetEnumerable(nSize);
530                     }
531                     catch (WrappedListException)
532                     {
533                         // Unable to read data
534                         return false;
535                     }
536                 }
537             }
538
539             opcodeRet = opcode;
540
541             return true;
542         }
543
544         /// <summary>
545         /// Convert value bytes into readable representation.
546         /// 
547         /// If list lengh is equal or lesser than 4 bytes then bytes are interpreted as integer value. Otherwise you will get hex representation of supplied data.
548         /// </summary>
549         /// <param name="bytes">Collection of value bytes.</param>
550         /// <returns>Formatted value.</returns>
551         public static string ValueString(IEnumerable<byte> bytes)
552         {
553             StringBuilder sb = new StringBuilder();
554
555             if (bytes.Count() <= 4)
556             {
557                 byte[] valueBytes = new byte[4] { 0, 0, 0, 0 };
558                 bytes.ToArray().CopyTo(valueBytes, valueBytes.Length - bytes.Count());
559
560                 sb.Append(Interop.BEBytesToUInt32(valueBytes));
561             }
562             else
563             {
564                 return Interop.ToHex(bytes);
565             }
566
567             return sb.ToString();
568         }
569
570         /// <summary>
571         /// Convert list of stack items into human readable representation.
572         /// </summary>
573         /// <param name="stackList">List of stack items.</param>
574         /// <returns>Formatted value.</returns>
575         public static string StackString(IList<IList<byte>> stackList)
576         {
577             StringBuilder sb = new StringBuilder();
578             foreach (IList<byte> bytesList in stackList)
579             {
580                 sb.Append(ValueString(bytesList));
581             }
582
583             return sb.ToString();
584         }
585
586         /// <summary>
587         /// Decode small integer
588         /// </summary>
589         /// <param name="opcode">Small integer opcode (OP_0 - OP_16)</param>
590         /// <returns>Small integer</returns>
591         public static int DecodeOP_N(opcodetype opcode)
592         {
593             if (opcode == opcodetype.OP_0)
594                 return 0;
595
596             // Only OP_n opcodes are supported, throw exception otherwise.
597             if (opcode < opcodetype.OP_1 || opcode > opcodetype.OP_16)
598                 throw new Exception("Invalid small integer opcode.");
599             return (int)opcode - (int)(opcodetype.OP_1 - 1);
600         }
601
602         /// <summary>
603         /// Converts small integer into opcode
604         /// </summary>
605         /// <param name="n">Small integer from the range of 0 up to 16.</param>
606         /// <returns>Corresponding opcode.</returns>
607         public static opcodetype EncodeOP_N(int n)
608         {
609             // The n value must be in the range of 0 to 16.
610             if (n < 0 || n > 16)
611                 throw new Exception("Invalid small integer value.");
612             if (n == 0)
613                 return opcodetype.OP_0;
614             return (opcodetype)(opcodetype.OP_1 + n - 1);
615         }
616
617         public static int ScriptSigArgsExpected(txnouttype t, IList<IEnumerable<byte>> solutions)
618         {
619             switch (t)
620             {
621                 case txnouttype.TX_NONSTANDARD:
622                     return -1;
623                 case txnouttype.TX_NULL_DATA:
624                     return 1;
625                 case txnouttype.TX_PUBKEY:
626                     return 1;
627                 case txnouttype.TX_PUBKEYHASH:
628                     return 2;
629                 case txnouttype.TX_MULTISIG:
630                     if (solutions.Count() < 1 || solutions.First().Count() < 1)
631                         return -1;
632                     return solutions.First().First() + 1;
633                 case txnouttype.TX_SCRIPTHASH:
634                     return 1; // doesn't include args needed by the script
635             }
636             return -1;
637         }
638
639         /// <summary>
640         /// Is it a standart type of scriptPubKey?
641         /// </summary>
642         /// <param name="scriptPubKey">CScript instance</param>
643         /// <param name="whichType">utut type</param>
644         /// <returns>Checking result</returns>
645         public static bool IsStandard(CScript scriptPubKey, out txnouttype whichType)
646         {
647             IList<IEnumerable<byte>> solutions = new List<IEnumerable<byte>>();
648
649             if (!Solver(scriptPubKey, out whichType, out solutions))
650             {
651                 // No solutions found
652                 return false;
653             }
654
655             if (whichType == txnouttype.TX_MULTISIG)
656             {
657                 // Additional verification of OP_CHECKMULTISIG arguments
658                 byte m = solutions.First().First();
659                 byte n = solutions.Last().First();
660
661                 // Support up to x-of-3 multisig txns as standard
662                 if (n < 1 || n > 3)
663                 {
664                     return false;
665                 }
666                 if (m < 1 || m > n)
667                 {
668                     return false;
669                 }
670             }
671
672             return whichType != txnouttype.TX_NONSTANDARD;
673         }
674
675         /// <summary>
676         /// Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
677         /// </summary>
678         /// <param name="scriptPubKey">CScript instance</param>
679         /// <param name="typeRet">Output type</param>
680         /// <param name="solutions">Set of solutions</param>
681         /// <returns>Result</returns>
682         public static bool Solver(CScript scriptPubKey, out txnouttype typeRet, out IList<IEnumerable<byte>> solutions)
683         {
684             solutions = new List<IEnumerable<byte>>();
685
686             // There are shortcuts for pay-to-script-hash and pay-to-pubkey-hash, which are more constrained than the other types:
687
688             // It is always OP_HASH160 20 [20 byte hash] OP_EQUAL
689             if (scriptPubKey.IsPayToScriptHash)
690             {
691                 typeRet = txnouttype.TX_SCRIPTHASH;
692
693                 // Take 20 bytes with offset of 2 bytes
694                 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(2).Take(20);
695                 solutions.Add(hashBytes);
696
697                 return true;
698             }
699
700             // It is always OP_DUP OP_HASH160 20 [20 byte hash] OP_EQUALVERIFY OP_CHECKSIG
701             if (scriptPubKey.IsPayToPubKeyHash)
702             {
703                 typeRet = txnouttype.TX_PUBKEYHASH;
704
705                 // Take 20 bytes with offset of 3 bytes
706                 IEnumerable<byte> hashBytes = scriptPubKey.Bytes.Skip(3).Take(20);
707                 solutions.Add(hashBytes);
708
709                 return true;
710             }
711
712             List<Tuple<txnouttype, IEnumerable<byte>>> templateTuples = new List<Tuple<txnouttype, IEnumerable<byte>>>();
713
714             // Sender provides pubkey, receiver adds signature
715             // [ECDSA public key] OP_CHECKSIG
716             templateTuples.Add(
717                 new Tuple<txnouttype, IEnumerable<byte>>(
718                     txnouttype.TX_PUBKEY,
719                     new byte[] { (byte)opcodetype.OP_PUBKEY, (byte)opcodetype.OP_CHECKSIG })
720             );
721
722             // Sender provides N pubkeys, receivers provides M signatures
723             // N [pubkey1] [pubkey2] ... [pubkeyN] M OP_CHECKMULTISIG
724             // Where N and M are small integer opcodes (OP1 ... OP_16)
725             templateTuples.Add(
726                 new Tuple<txnouttype, IEnumerable<byte>>(
727                     txnouttype.TX_MULTISIG,
728                     new byte[] { (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_PUBKEYS, (byte)opcodetype.OP_SMALLINTEGER, (byte)opcodetype.OP_CHECKMULTISIG })
729             );
730
731             // Data-carrying output
732             // OP_RETURN [up to 80 bytes of data]
733             templateTuples.Add(
734                 new Tuple<txnouttype, IEnumerable<byte>>(
735                     txnouttype.TX_NULL_DATA,
736                     new byte[] { (byte)opcodetype.OP_RETURN, (byte)opcodetype.OP_SMALLDATA })
737             );
738
739             // Nonstandard tx output
740             typeRet = txnouttype.TX_NONSTANDARD;
741
742             foreach (Tuple<txnouttype, IEnumerable<byte>> templateTuple in templateTuples)
743             {
744                 CScript script1 = scriptPubKey;
745                 CScript script2 = new CScript(templateTuple.Item2);
746
747                 opcodetype opcode1, opcode2;
748
749                 // Compare
750                 ByteQueue wl1 = script1.GetWrappedList();
751                 ByteQueue wl2 = script2.GetWrappedList();
752
753                 IEnumerable<byte> args1, args2;
754
755                 byte last1 = script1.Bytes.Last();
756                 byte last2 = script2.Bytes.Last();
757
758                 while (true)
759                 {
760                     if (wl1.GetCurrent() == last1 && wl2.GetCurrent() == last2)
761                     {
762                         // Found a match
763                         typeRet = templateTuple.Item1;
764                         if (typeRet == txnouttype.TX_MULTISIG)
765                         {
766                             // Additional checks for TX_MULTISIG:
767                             byte m = solutions.First().First();
768                             byte n = solutions.Last().First();
769
770                             if (m < 1 || n < 1 || m > n || solutions.Count - 2 != n)
771                             {
772                                 return false;
773                             }
774                         }
775                         return true;
776                     }
777
778                     if (!GetOp(ref wl1, out opcode1, out args1))
779                     {
780                         break;
781                     }
782                     if (!GetOp(ref wl2, out opcode2, out args2))
783                     {
784                         break;
785                     }
786
787                     // Template matching opcodes:
788                     if (opcode2 == opcodetype.OP_PUBKEYS)
789                     {
790                         while (args1.Count() >= 33 && args1.Count() <= 120)
791                         {
792                             solutions.Add(args1);
793                             if (!GetOp(ref wl1, out opcode1, out args1))
794                             {
795                                 break;
796                             }
797                         }
798                         if (!GetOp(ref wl2, out opcode2, out args2))
799                             break;
800                         // Normal situation is to fall through
801                         // to other if/else statements
802                     }
803                     if (opcode2 == opcodetype.OP_PUBKEY)
804                     {
805                         if (args1.Count() < 33 || args1.Count() > 120)
806                         {
807                             break;
808                         }
809                         solutions.Add(args1);
810                     }
811                     else if (opcode2 == opcodetype.OP_PUBKEYHASH)
812                     {
813                         if (args1.Count() != 20) // hash160 size
814                         {
815                             break;
816                         }
817                         solutions.Add(args1);
818                     }
819                     else if (opcode2 == opcodetype.OP_SMALLINTEGER)
820                     {
821                         // Single-byte small integer pushed onto solutions
822                         if (opcode1 == opcodetype.OP_0 || (opcode1 >= opcodetype.OP_1 && opcode1 <= opcodetype.OP_16))
823                         {
824                             byte n = (byte)DecodeOP_N(opcode1);
825                             solutions.Add(new byte[] { n });
826                         }
827                         else
828                         {
829                             break;
830                         }
831                     }
832                     else if (opcode2 == opcodetype.OP_SMALLDATA)
833                     {
834                         // small pushdata, <= 80 bytes
835                         if (args1.Count() > 80)
836                         {
837                             break;
838                         }
839                     }
840                     else if (opcode1 != opcode2 || !args1.SequenceEqual(args2))
841                     {
842                         // Others must match exactly
843                         break;
844                     }
845                 }
846             }
847
848             solutions.Clear();
849             typeRet = txnouttype.TX_NONSTANDARD;
850
851             return false;
852         }
853
854         public static Hash256 SignatureHash(CScript scriptCode, CTransaction txTo, int nIn, int nHashType)
855         {
856             if (nIn >= txTo.vin.Length)
857             {
858                 StringBuilder sb = new StringBuilder();
859                 sb.AppendFormat("ERROR: SignatureHash() : nIn={0} out of range\n", nIn);
860                 throw new ArgumentOutOfRangeException("nIn", sb.ToString());
861             }
862
863             CTransaction txTmp = new CTransaction(txTo);
864
865             // In case concatenating two scripts ends up with two codeseparators,
866             // or an extra one at the end, this prevents all those possible incompatibilities.
867             scriptCode.RemovePattern(new byte[] { (byte)opcodetype.OP_CODESEPARATOR });
868
869             // Blank out other inputs' signatures
870             for (int i = 0; i < txTmp.vin.Length; i++)
871             {
872                 txTmp.vin[i].scriptSig = new CScript();
873             }
874             txTmp.vin[nIn].scriptSig = scriptCode;
875
876             // Blank out some of the outputs
877             if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_NONE)
878             {
879                 // Wildcard payee
880                 txTmp.vout = new CTxOut[0];
881
882                 // Let the others update at will
883                 for (int i = 0; i < txTmp.vin.Length; i++)
884                 {
885                     if (i != nIn)
886                     {
887                         txTmp.vin[i].nSequence = 0;
888                     }
889                 }
890             }
891             else if ((nHashType & 0x1f) == (int)sigflag.SIGHASH_SINGLE)
892             {
893                 // Only lock-in the txout payee at same index as txin
894                 int nOut = nIn;
895                 if (nOut >= txTmp.vout.Length)
896                 {
897                     StringBuilder sb = new StringBuilder();
898                     sb.AppendFormat("ERROR: SignatureHash() : nOut={0} out of range\n", nOut);
899                     throw new ArgumentOutOfRangeException("nOut", sb.ToString());
900                 }
901                 Array.Resize(ref txTmp.vout, nOut + 1);
902
903                 for (int i = 0; i < nOut; i++)
904                 {
905                     txTmp.vout[i] = new CTxOut();
906                 }
907
908                 // Let the others update at will
909                 for (int i = 0; i < txTmp.vin.Length; i++)
910                 {
911                     if (i != nIn)
912                     {
913                         txTmp.vin[i].nSequence = 0;
914                     }
915                 }
916             }
917
918             // Blank out other inputs completely, not recommended for open transactions
919             if ((nHashType & (int)sigflag.SIGHASH_ANYONECANPAY) != 0)
920             {
921                 txTmp.vin[0] = txTmp.vin[nIn];
922                 Array.Resize(ref txTmp.vin, 1);
923             }
924
925             // Serialize and hash
926             List<byte> b = new List<byte>();
927             b.AddRange(txTmp.Bytes);
928             b.AddRange(BitConverter.GetBytes(nHashType));
929
930             return Hash256.Compute256(b);
931         }
932
933     };
934 }