btcruby 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +3 -1
 - data/RELEASE_NOTES.md +8 -0
 - data/lib/btcruby.rb +6 -1
 - data/lib/btcruby/openssl.rb +23 -9
 - data/lib/btcruby/{transaction_outpoint.rb → outpoint.rb} +14 -1
 - data/lib/btcruby/script/cltv_plugin.rb +63 -0
 - data/lib/btcruby/script/p2sh_plugin.rb +71 -0
 - data/lib/btcruby/script/script.rb +7 -1
 - data/lib/btcruby/script/script_error.rb +1 -1
 - data/lib/btcruby/script/script_interpreter.rb +230 -120
 - data/lib/btcruby/script/script_interpreter_plugin.rb +67 -0
 - data/lib/btcruby/script/script_number.rb +2 -2
 - data/lib/btcruby/script/transaction_signature_checker.rb +4 -1
 - data/lib/btcruby/secp256k1.rb +77 -0
 - data/lib/btcruby/transaction.rb +5 -4
 - data/lib/btcruby/transaction_input.rb +15 -2
 - data/lib/btcruby/transaction_output.rb +2 -2
 - data/lib/btcruby/validation.rb +90 -0
 - data/lib/btcruby/version.rb +1 -1
 - data/spec/data/script_invalid.rb +814 -0
 - data/spec/data/script_valid.rb +911 -0
 - data/spec/data/tx_invalid.rb +197 -0
 - data/spec/data/tx_valid.rb +233 -0
 - data/spec/open_assets/issuance_id_spec.rb +1 -1
 - data/spec/script_interpreter_spec.rb +85 -0
 - data/spec/secp256k1_spec.rb +33 -0
 - data/spec/spec_helper.rb +115 -0
 - data/spec/transaction_spec.rb +153 -0
 - metadata +16 -3
 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative '../lib/btcruby/secp256k1'
         
     | 
| 
      
 3 
     | 
    
         
            +
            describe BTC::Secp256k1 do
         
     | 
| 
      
 4 
     | 
    
         
            +
              
         
     | 
| 
      
 5 
     | 
    
         
            +
              def verify_rfc6979_signature(keyhex, msg, sighex)
         
     | 
| 
      
 6 
     | 
    
         
            +
                key = BTC::Key.new(private_key: keyhex.from_hex)
         
     | 
| 
      
 7 
     | 
    
         
            +
                hash = BTC.sha256(msg)
         
     | 
| 
      
 8 
     | 
    
         
            +
                sig = BTC::Secp256k1.ecdsa_signature(hash, key.private_key)
         
     | 
| 
      
 9 
     | 
    
         
            +
                sig.to_hex.must_equal sighex
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it "should produce deterministic ECDSA signatures Bitcoin-canonical using nonce from RFC6979" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                verify_rfc6979_signature("cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50",
         
     | 
| 
      
 14 
     | 
    
         
            +
                                         "sample",
         
     | 
| 
      
 15 
     | 
    
         
            +
                                         "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124")
         
     | 
| 
      
 16 
     | 
    
         
            +
                verify_rfc6979_signature("0000000000000000000000000000000000000000000000000000000000000001",
         
     | 
| 
      
 17 
     | 
    
         
            +
                                         "Satoshi Nakamoto",
         
     | 
| 
      
 18 
     | 
    
         
            +
                                         "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5")
         
     | 
| 
      
 19 
     | 
    
         
            +
                verify_rfc6979_signature("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
         
     | 
| 
      
 20 
     | 
    
         
            +
                                         "Satoshi Nakamoto",
         
     | 
| 
      
 21 
     | 
    
         
            +
                                         "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5")
         
     | 
| 
      
 22 
     | 
    
         
            +
                verify_rfc6979_signature("f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181",
         
     | 
| 
      
 23 
     | 
    
         
            +
                                         "Alan Turing",
         
     | 
| 
      
 24 
     | 
    
         
            +
                                         "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea")
         
     | 
| 
      
 25 
     | 
    
         
            +
                verify_rfc6979_signature("0000000000000000000000000000000000000000000000000000000000000001",
         
     | 
| 
      
 26 
     | 
    
         
            +
                                         "All those moments will be lost in time, like tears in rain. Time to die...",
         
     | 
| 
      
 27 
     | 
    
         
            +
                                         "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21")
         
     | 
| 
      
 28 
     | 
    
         
            +
                verify_rfc6979_signature("e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2",
         
     | 
| 
      
 29 
     | 
    
         
            +
                                         "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!",
         
     | 
| 
      
 30 
     | 
    
         
            +
                                         "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6")
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | 
         @@ -6,3 +6,118 @@ require_relative '../lib/btcruby/extensions' 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            # So every test can access classes directly without prefixing them with BTC::
         
     | 
| 
       8 
8 
     | 
    
         
             
            include BTC
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            # Script helper used by transaction_spec and script_interpreter_spec
         
     | 
| 
      
 11 
     | 
    
         
            +
            FLAGS_MAP = {
         
     | 
| 
      
 12 
     | 
    
         
            +
                "" =>                           ScriptFlags::SCRIPT_VERIFY_NONE,
         
     | 
| 
      
 13 
     | 
    
         
            +
                "NONE" =>                       ScriptFlags::SCRIPT_VERIFY_NONE,
         
     | 
| 
      
 14 
     | 
    
         
            +
                "P2SH" =>                       ScriptFlags::SCRIPT_VERIFY_P2SH,
         
     | 
| 
      
 15 
     | 
    
         
            +
                "STRICTENC" =>                  ScriptFlags::SCRIPT_VERIFY_STRICTENC,
         
     | 
| 
      
 16 
     | 
    
         
            +
                "DERSIG" =>                     ScriptFlags::SCRIPT_VERIFY_DERSIG,
         
     | 
| 
      
 17 
     | 
    
         
            +
                "LOW_S" =>                      ScriptFlags::SCRIPT_VERIFY_LOW_S,
         
     | 
| 
      
 18 
     | 
    
         
            +
                "NULLDUMMY" =>                  ScriptFlags::SCRIPT_VERIFY_NULLDUMMY,
         
     | 
| 
      
 19 
     | 
    
         
            +
                "SIGPUSHONLY" =>                ScriptFlags::SCRIPT_VERIFY_SIGPUSHONLY,
         
     | 
| 
      
 20 
     | 
    
         
            +
                "MINIMALDATA" =>                ScriptFlags::SCRIPT_VERIFY_MINIMALDATA,
         
     | 
| 
      
 21 
     | 
    
         
            +
                "DISCOURAGE_UPGRADABLE_NOPS" => ScriptFlags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
         
     | 
| 
      
 22 
     | 
    
         
            +
                "CLEANSTACK" =>                 ScriptFlags::SCRIPT_VERIFY_CLEANSTACK,
         
     | 
| 
      
 23 
     | 
    
         
            +
                "CHECKLOCKTIMEVERIFY" =>        ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
         
     | 
| 
      
 24 
     | 
    
         
            +
            }
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            def parse_script(json_script, expected_result = true)
         
     | 
| 
      
 27 
     | 
    
         
            +
              # Note: individual 0xXX bytes may not be individually valid pushdatas, but will be valid when composed together.
         
     | 
| 
      
 28 
     | 
    
         
            +
              # Since Script parses binary string right away, we need to compose all distinct bytes in a single hex string.
         
     | 
| 
      
 29 
     | 
    
         
            +
              orig_string = json_script
         
     | 
| 
      
 30 
     | 
    
         
            +
              json_script = json_script.dup
         
     | 
| 
      
 31 
     | 
    
         
            +
              oldsize = json_script.size + 1
         
     | 
| 
      
 32 
     | 
    
         
            +
              while json_script.size != oldsize
         
     | 
| 
      
 33 
     | 
    
         
            +
                oldsize = json_script.size
         
     | 
| 
      
 34 
     | 
    
         
            +
                json_script.gsub!(/0x([0-9a-fA-F]+)\s+0x/, "0x\\1")
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              json_script.split(" ").inject(Script.new) do |parsed_script, x|
         
     | 
| 
      
 37 
     | 
    
         
            +
                if x.size == 0
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # Empty string, ignore.
         
     | 
| 
      
 39 
     | 
    
         
            +
                  parsed_script
         
     | 
| 
      
 40 
     | 
    
         
            +
                elsif x =~ /^-?\d+$/
         
     | 
| 
      
 41 
     | 
    
         
            +
                  # Number
         
     | 
| 
      
 42 
     | 
    
         
            +
                  n = x.to_i
         
     | 
| 
      
 43 
     | 
    
         
            +
                  if (n == -1) || (n >= 1 and n <= 16)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    parsed_script << Opcode.opcode_for_small_integer(n)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  else
         
     | 
| 
      
 46 
     | 
    
         
            +
                    parsed_script << ScriptNumber.new(integer: n).data
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                elsif x[0,2] == "0x"
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # Raw hex data, inserted NOT pushed onto stack:
         
     | 
| 
      
 50 
     | 
    
         
            +
                  data = BTC.from_hex(x[2..-1])
         
     | 
| 
      
 51 
     | 
    
         
            +
                  Script.new(data: parsed_script.data + data)
         
     | 
| 
      
 52 
     | 
    
         
            +
                elsif x =~ /^'.*'$/
         
     | 
| 
      
 53 
     | 
    
         
            +
                  # Single-quoted string, pushed as data.
         
     | 
| 
      
 54 
     | 
    
         
            +
                  parsed_script << x[1..-2]
         
     | 
| 
      
 55 
     | 
    
         
            +
                else
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # opcode, e.g. OP_ADD or ADD:
         
     | 
| 
      
 57 
     | 
    
         
            +
                  opcode = Opcode.opcode_for_name("OP_" + x)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  opcode = Opcode.opcode_for_name(x) if opcode == OP_INVALIDOPCODE
         
     | 
| 
      
 59 
     | 
    
         
            +
                  parsed_script << opcode
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            rescue => e
         
     | 
| 
      
 63 
     | 
    
         
            +
              if expected_result
         
     | 
| 
      
 64 
     | 
    
         
            +
                # puts "json_script = #{orig_string.inspect}"
         
     | 
| 
      
 65 
     | 
    
         
            +
                # puts "json_script = #{json_script.inspect}"
         
     | 
| 
      
 66 
     | 
    
         
            +
                # puts "EXCEPTION: #{e}"
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
              return nil
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            def parse_flags(string)
         
     | 
| 
      
 72 
     | 
    
         
            +
              string.split(",").inject(0) do |flags, x|
         
     | 
| 
      
 73 
     | 
    
         
            +
                f = FLAGS_MAP[x] or raise RuntimeError, "unrecognized script flag: #{x.inspect}"
         
     | 
| 
      
 74 
     | 
    
         
            +
                flags | f
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            def build_crediting_transaction(scriptPubKey)
         
     | 
| 
      
 79 
     | 
    
         
            +
              txCredit = Transaction.new;
         
     | 
| 
      
 80 
     | 
    
         
            +
              txCredit.version = 1;
         
     | 
| 
      
 81 
     | 
    
         
            +
              txCredit.lock_time = 0;
         
     | 
| 
      
 82 
     | 
    
         
            +
              txCredit.add_input(TransactionInput.new(
         
     | 
| 
      
 83 
     | 
    
         
            +
                previous_hash: nil,
         
     | 
| 
      
 84 
     | 
    
         
            +
                coinbase_data: (Script.new << ScriptNumber.new(integer:0) << ScriptNumber.new(integer:0)).data
         
     | 
| 
      
 85 
     | 
    
         
            +
              ))
         
     | 
| 
      
 86 
     | 
    
         
            +
              txCredit.add_output(TransactionOutput.new(
         
     | 
| 
      
 87 
     | 
    
         
            +
                script: scriptPubKey,
         
     | 
| 
      
 88 
     | 
    
         
            +
                value: 0
         
     | 
| 
      
 89 
     | 
    
         
            +
              ))
         
     | 
| 
      
 90 
     | 
    
         
            +
              txCredit
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            def build_spending_transaction(scriptSig, txCredit)
         
     | 
| 
      
 94 
     | 
    
         
            +
              txSpend = Transaction.new
         
     | 
| 
      
 95 
     | 
    
         
            +
              txSpend.version = 1;
         
     | 
| 
      
 96 
     | 
    
         
            +
              txSpend.lock_time = 0;
         
     | 
| 
      
 97 
     | 
    
         
            +
              txSpend.add_input(TransactionInput.new(
         
     | 
| 
      
 98 
     | 
    
         
            +
                previous_hash: txCredit.transaction_hash,
         
     | 
| 
      
 99 
     | 
    
         
            +
                previous_index: 0,
         
     | 
| 
      
 100 
     | 
    
         
            +
                signature_script: scriptSig
         
     | 
| 
      
 101 
     | 
    
         
            +
              ))
         
     | 
| 
      
 102 
     | 
    
         
            +
              txSpend.add_output(TransactionOutput.new(
         
     | 
| 
      
 103 
     | 
    
         
            +
                script: Script.new,
         
     | 
| 
      
 104 
     | 
    
         
            +
                value: 0
         
     | 
| 
      
 105 
     | 
    
         
            +
              ))
         
     | 
| 
      
 106 
     | 
    
         
            +
              txSpend
         
     | 
| 
      
 107 
     | 
    
         
            +
            end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
            # ctx = build_crediting_transaction(Script.new)
         
     | 
| 
      
 110 
     | 
    
         
            +
            # stx = build_spending_transaction(Script.new, build_crediting_transaction(Script.new))
         
     | 
| 
      
 111 
     | 
    
         
            +
            # 
         
     | 
| 
      
 112 
     | 
    
         
            +
            # puts "crediting tx: #{ctx.transaction_id}" # 7f33a2f5ace097f071010d5105e7fd01f22c83d8d5daa741a41f2a630a2af23b
         
     | 
| 
      
 113 
     | 
    
         
            +
            # puts "spending tx:  #{stx.transaction_id}" # add55eb99bb1f653ab822ea4177cb0f9673bcc5c2c4c729894ab0c626c8fa1e1
         
     | 
| 
      
 114 
     | 
    
         
            +
            # 
         
     | 
| 
      
 115 
     | 
    
         
            +
            # puts "crediting tx: #{ctx.data.to_hex}"
         
     | 
| 
      
 116 
     | 
    
         
            +
            # puts "spending tx:  #{stx.data.to_hex}"
         
     | 
| 
      
 117 
     | 
    
         
            +
            # From Bitcoin Core:
         
     | 
| 
      
 118 
     | 
    
         
            +
            # ctxdummy: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff020000ffffffff0100000000000000000000000000; 
         
     | 
| 
      
 119 
     | 
    
         
            +
            # ID = 7f33a2f5ace097f071010d5105e7fd01f22c83d8d5daa741a41f2a630a2af23b
         
     | 
| 
      
 120 
     | 
    
         
            +
            # stxdummy: 01000000013bf22a0a632a1fa441a7dad5d8832cf201fde705510d0171f097e0acf5a2337f0000000000ffffffff0100000000000000000000000000; 
         
     | 
| 
      
 121 
     | 
    
         
            +
            # ID = add55eb99bb1f653ab822ea4177cb0f9673bcc5c2c4c729894ab0c626c8fa1e1
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
    
        data/spec/transaction_spec.rb
    CHANGED
    
    | 
         @@ -1,4 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require_relative 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'data/tx_valid'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'data/tx_invalid'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       2 
5 
     | 
    
         
             
            describe BTC::Transaction do
         
     | 
| 
       3 
6 
     | 
    
         | 
| 
       4 
7 
     | 
    
         
             
              it "should have core attributes" do
         
     | 
| 
         @@ -19,6 +22,156 @@ describe BTC::Transaction do 
     | 
|
| 
       19 
22 
     | 
    
         
             
                })
         
     | 
| 
       20 
23 
     | 
    
         | 
| 
       21 
24 
     | 
    
         
             
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
              
         
     | 
| 
      
 26 
     | 
    
         
            +
              describe "Bitcoin Core test vectors" do
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                module TxTestHelper
         
     | 
| 
      
 29 
     | 
    
         
            +
                  extend self
         
     | 
| 
      
 30 
     | 
    
         
            +
                  
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # Read tests from test/data/tx_valid.json
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # Format is an array of arrays
         
     | 
| 
      
 33 
     | 
    
         
            +
                  # Inner arrays are either [ "comment" ]
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], serializedTransaction, verifyFlags
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # ... where all scripts are stringified scripts.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def parse_tests(records, expected_result)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    comment = nil
         
     | 
| 
      
 40 
     | 
    
         
            +
                    records.each do |test|
         
     | 
| 
      
 41 
     | 
    
         
            +
                      if test[0].is_a?(Array)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        if test.size != 3 || !test[1].is_a?(String) || !test[2].is_a?(String)
         
     | 
| 
      
 43 
     | 
    
         
            +
                          raise "Bad test: #{test.inspect} (#{test.size} #{test[1].class} #{test[2].class})"
         
     | 
| 
      
 44 
     | 
    
         
            +
                        end
         
     | 
| 
      
 45 
     | 
    
         
            +
                        mapprevOutScriptPubKeys = {} # Outpoint => Script
         
     | 
| 
      
 46 
     | 
    
         
            +
                        inputs = test[0]
         
     | 
| 
      
 47 
     | 
    
         
            +
                        inputs.each do |input|
         
     | 
| 
      
 48 
     | 
    
         
            +
                          raise "Bad test: input is not an array: #{test.inspect}" if !input.is_a?(Array)
         
     | 
| 
      
 49 
     | 
    
         
            +
                          raise "Bad test: input is an array of 3 items: #{test.inspect}" if input.size != 3
         
     | 
| 
      
 50 
     | 
    
         
            +
                          previd, previndex, scriptstring = input
         
     | 
| 
      
 51 
     | 
    
         
            +
                        
         
     | 
| 
      
 52 
     | 
    
         
            +
                          outpoint = Outpoint.new(transaction_id: previd, index: previndex)
         
     | 
| 
      
 53 
     | 
    
         
            +
                        
         
     | 
| 
      
 54 
     | 
    
         
            +
                          mapprevOutScriptPubKeys[outpoint] = parse_script(scriptstring)
         
     | 
| 
      
 55 
     | 
    
         
            +
                        end
         
     | 
| 
      
 56 
     | 
    
         
            +
                      
         
     | 
| 
      
 57 
     | 
    
         
            +
                        tx = Transaction.new(hex: test[1])
         
     | 
| 
      
 58 
     | 
    
         
            +
                        flags = parse_flags(test[2])
         
     | 
| 
      
 59 
     | 
    
         
            +
                        
         
     | 
| 
      
 60 
     | 
    
         
            +
                        if debug_filter(test)
         
     | 
| 
      
 61 
     | 
    
         
            +
                          validation_proc = lambda do
         
     | 
| 
      
 62 
     | 
    
         
            +
                            validation_passed = Validation.new.check_transaction(tx, ValidationState.new)
         
     | 
| 
      
 63 
     | 
    
         
            +
                            if expected_result
         
     | 
| 
      
 64 
     | 
    
         
            +
                              validation_passed.must_equal expected_result
         
     | 
| 
      
 65 
     | 
    
         
            +
                            end
         
     | 
| 
      
 66 
     | 
    
         
            +
                            script_passed = false
         
     | 
| 
      
 67 
     | 
    
         
            +
                          
         
     | 
| 
      
 68 
     | 
    
         
            +
                            if validation_passed
         
     | 
| 
      
 69 
     | 
    
         
            +
                              tx.inputs.each do |txin|
         
     | 
| 
      
 70 
     | 
    
         
            +
                                output_script = mapprevOutScriptPubKeys[txin.outpoint]
         
     | 
| 
      
 71 
     | 
    
         
            +
                                raise "Bad test: output script not found: #{test.inspect}" if !output_script
         
     | 
| 
      
 72 
     | 
    
         
            +
                                sig_script = txin.signature_script
         
     | 
| 
      
 73 
     | 
    
         
            +
                                if !sig_script
         
     | 
| 
      
 74 
     | 
    
         
            +
                                  sig_script = Script.new(data: txin.coinbase_data)
         
     | 
| 
      
 75 
     | 
    
         
            +
                                end
         
     | 
| 
      
 76 
     | 
    
         
            +
                                
         
     | 
| 
      
 77 
     | 
    
         
            +
                                checker = TransactionSignatureChecker.new(transaction: tx, input_index: txin.index)
         
     | 
| 
      
 78 
     | 
    
         
            +
                                plugins = []
         
     | 
| 
      
 79 
     | 
    
         
            +
                                plugins << P2SHPlugin.new if (flags & ScriptFlags::SCRIPT_VERIFY_P2SH) != 0
         
     | 
| 
      
 80 
     | 
    
         
            +
                                plugins << CLTVPlugin.new if (flags & ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) != 0
         
     | 
| 
      
 81 
     | 
    
         
            +
                                interpreter = ScriptInterpreter.new(
         
     | 
| 
      
 82 
     | 
    
         
            +
                                  flags: flags,
         
     | 
| 
      
 83 
     | 
    
         
            +
                                  plugins: plugins,
         
     | 
| 
      
 84 
     | 
    
         
            +
                                  signature_checker: checker,
         
     | 
| 
      
 85 
     | 
    
         
            +
                                  raise_on_failure: expected_result,
         
     | 
| 
      
 86 
     | 
    
         
            +
                                )
         
     | 
| 
      
 87 
     | 
    
         
            +
                                #Diagnostics.current.trace do
         
     | 
| 
      
 88 
     | 
    
         
            +
                                  script_passed = interpreter.verify_script(signature_script: sig_script, output_script: output_script)
         
     | 
| 
      
 89 
     | 
    
         
            +
                                  if !script_passed
         
     | 
| 
      
 90 
     | 
    
         
            +
                                    break
         
     | 
| 
      
 91 
     | 
    
         
            +
                                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                                #end
         
     | 
| 
      
 93 
     | 
    
         
            +
                              end
         
     | 
| 
      
 94 
     | 
    
         
            +
                            end
         
     | 
| 
      
 95 
     | 
    
         
            +
                            (script_passed && validation_passed).must_equal expected_result
         
     | 
| 
      
 96 
     | 
    
         
            +
                          end # proc
         
     | 
| 
      
 97 
     | 
    
         
            +
                          
         
     | 
| 
      
 98 
     | 
    
         
            +
                          yield(comment || test.inspect, validation_proc)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        end # if not filtered
         
     | 
| 
      
 100 
     | 
    
         
            +
                        
         
     | 
| 
      
 101 
     | 
    
         
            +
                        comment = nil
         
     | 
| 
      
 102 
     | 
    
         
            +
                      else
         
     | 
| 
      
 103 
     | 
    
         
            +
                        comment ||= ""
         
     | 
| 
      
 104 
     | 
    
         
            +
                        comment += test[0].gsub(/\.$/,"") + ". "
         
     | 
| 
      
 105 
     | 
    
         
            +
                        comment.gsub!(/\. $/, "")
         
     | 
| 
      
 106 
     | 
    
         
            +
                      end
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                  
         
     | 
| 
      
 110 
     | 
    
         
            +
                  def debug_filter(test)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    
         
     | 
| 
      
 112 
     | 
    
         
            +
                    #return test.inspect[%{010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000}]
         
     | 
| 
      
 113 
     | 
    
         
            +
                    
         
     | 
| 
      
 114 
     | 
    
         
            +
                    
         
     | 
| 
      
 115 
     | 
    
         
            +
                    # !!! SIGHASH_SINGLE tx: afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae hashed for input 0: 1eccdc1f7a4783924a49113b491a847de2f89a1e7d73b1ae561d80f918035f46
         
     | 
| 
      
 116 
     | 
    
         
            +
                    # !!! SIGHASH_SINGLE tx: afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae hashed for input 1: 1943e87af64d0bde608a85330f09aa5c9887a4fdfd9ca6d7a139bef27fee8e3b
         
     | 
| 
      
 117 
     | 
    
         
            +
                    # !!! SIGHASH_SINGLE tx: afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae hashed for input 2: 1c1f068da6a721f2ecb0fdac3b8adcb4073fee34506971472d29d305507894d6
         
     | 
| 
      
 118 
     | 
    
         
            +
                    #return test.inspect[%{DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG}]
         
     | 
| 
      
 119 
     | 
    
         
            +
                    
         
     | 
| 
      
 120 
     | 
    
         
            +
                    #return test.inspect[%{[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"]}]
         
     | 
| 
      
 121 
     | 
    
         
            +
                    true
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
                  
         
     | 
| 
      
 124 
     | 
    
         
            +
                  # def verify_script(tx, txin, sig_script, output_script, flags, expected_result, record)
         
     | 
| 
      
 125 
     | 
    
         
            +
                  #   checker = TransactionSignatureChecker.new(transaction: tx, input_index: txin.index)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  #   plugins = []
         
     | 
| 
      
 127 
     | 
    
         
            +
                  #   plugins << P2SHPlugin.new if (flags & ScriptFlags::SCRIPT_VERIFY_P2SH) != 0
         
     | 
| 
      
 128 
     | 
    
         
            +
                  #   plugins << CLTVPlugin.new if (flags & ScriptFlags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) != 0
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #   interpreter = ScriptInterpreter.new(
         
     | 
| 
      
 130 
     | 
    
         
            +
                  #     flags: flags,
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #     plugins: plugins,
         
     | 
| 
      
 132 
     | 
    
         
            +
                  #     signature_checker: checker,
         
     | 
| 
      
 133 
     | 
    
         
            +
                  #     raise_on_failure: expected_result,
         
     | 
| 
      
 134 
     | 
    
         
            +
                  #   )
         
     | 
| 
      
 135 
     | 
    
         
            +
                  #   #Diagnostics.current.trace do
         
     | 
| 
      
 136 
     | 
    
         
            +
                  #     checked = Validation.new.check_transaction(tx, ValidationState.new)
         
     | 
| 
      
 137 
     | 
    
         
            +
                  #     if expected_result
         
     | 
| 
      
 138 
     | 
    
         
            +
                  #       checked.must_equal expected_result
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 140 
     | 
    
         
            +
                  #     result = false
         
     | 
| 
      
 141 
     | 
    
         
            +
                  #     if checked
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #       result = interpreter.verify_script(signature_script: sig_script, output_script: output_script)
         
     | 
| 
      
 143 
     | 
    
         
            +
                  #       if result != expected_result
         
     | 
| 
      
 144 
     | 
    
         
            +
                  #         # puts "Failed scripts: #{sig_script.to_s.inspect} #{output_script.to_s.inspect} flags #{flags}, expected to #{expected_result ? 'succeed' : 'fail'}".gsub(/OP_/, "")
         
     | 
| 
      
 145 
     | 
    
         
            +
                  #         # puts "Error: #{interpreter.error.inspect}"
         
     | 
| 
      
 146 
     | 
    
         
            +
                  #         #debug("Failed #{expected_result ? 'valid' : 'invalid'} script: #{sig_script.to_s.inspect} #{output_script.to_s.inspect} flags #{flags} -- #{record.inspect}")
         
     | 
| 
      
 147 
     | 
    
         
            +
                  #       end
         
     | 
| 
      
 148 
     | 
    
         
            +
                  #     end
         
     | 
| 
      
 149 
     | 
    
         
            +
                  #     puts
         
     | 
| 
      
 150 
     | 
    
         
            +
                  #     puts record.inspect
         
     | 
| 
      
 151 
     | 
    
         
            +
                  #     puts "---------------------------" 
         
     | 
| 
      
 152 
     | 
    
         
            +
                  #     puts (result && checked).inspect
         
     | 
| 
      
 153 
     | 
    
         
            +
                  #     puts
         
     | 
| 
      
 154 
     | 
    
         
            +
                  #     (result && checked).must_equal expected_result
         
     | 
| 
      
 155 
     | 
    
         
            +
                  #   #end
         
     | 
| 
      
 156 
     | 
    
         
            +
                  # end
         
     | 
| 
      
 157 
     | 
    
         
            +
                  
         
     | 
| 
      
 158 
     | 
    
         
            +
                  
         
     | 
| 
      
 159 
     | 
    
         
            +
                end
         
     | 
| 
      
 160 
     | 
    
         
            +
                
         
     | 
| 
      
 161 
     | 
    
         
            +
                TxTestHelper.parse_tests(ValidTxs, true) do |comment, validation_proc|
         
     | 
| 
      
 162 
     | 
    
         
            +
                  it "should validate transaction: #{comment}" do
         
     | 
| 
      
 163 
     | 
    
         
            +
                    validation_proc.call
         
     | 
| 
      
 164 
     | 
    
         
            +
                    #TxTestHelper.verify_script(tx, txin, signature_script, output_script, flags, expected_result, record)
         
     | 
| 
      
 165 
     | 
    
         
            +
                  end
         
     | 
| 
      
 166 
     | 
    
         
            +
                end
         
     | 
| 
      
 167 
     | 
    
         
            +
                
         
     | 
| 
      
 168 
     | 
    
         
            +
                TxTestHelper.parse_tests(InvalidTxs, false) do |comment, validation_proc| # |helper, tx, txin, signature_script, output_script, flags, expected_result, record, comment|
         
     | 
| 
      
 169 
     | 
    
         
            +
                  it "should fail transaction: #{comment}" do
         
     | 
| 
      
 170 
     | 
    
         
            +
                    validation_proc.call
         
     | 
| 
      
 171 
     | 
    
         
            +
                    #TxTestHelper.verify_script(tx, txin, signature_script, output_script, flags, expected_result, record)
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
       22 
175 
     | 
    
         | 
| 
       23 
176 
     | 
    
         
             
              describe "Hash <-> ID conversion" do
         
     | 
| 
       24 
177 
     | 
    
         
             
                before do
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: btcruby
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.1.2
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Oleg Andreev
         
     | 
| 
         @@ -9,7 +9,7 @@ authors: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date: 2015- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2015-08-17 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: ffi
         
     | 
| 
         @@ -101,18 +101,23 @@ files: 
     | 
|
| 
       101 
101 
     | 
    
         
             
            - lib/btcruby/open_assets/asset_transaction_output.rb
         
     | 
| 
       102 
102 
     | 
    
         
             
            - lib/btcruby/open_assets/issuance_id.rb
         
     | 
| 
       103 
103 
     | 
    
         
             
            - lib/btcruby/openssl.rb
         
     | 
| 
      
 104 
     | 
    
         
            +
            - lib/btcruby/outpoint.rb
         
     | 
| 
       104 
105 
     | 
    
         
             
            - lib/btcruby/proof_of_work.rb
         
     | 
| 
       105 
106 
     | 
    
         
             
            - lib/btcruby/safety.rb
         
     | 
| 
      
 107 
     | 
    
         
            +
            - lib/btcruby/script/cltv_plugin.rb
         
     | 
| 
       106 
108 
     | 
    
         
             
            - lib/btcruby/script/opcode.rb
         
     | 
| 
      
 109 
     | 
    
         
            +
            - lib/btcruby/script/p2sh_plugin.rb
         
     | 
| 
       107 
110 
     | 
    
         
             
            - lib/btcruby/script/script.rb
         
     | 
| 
       108 
111 
     | 
    
         
             
            - lib/btcruby/script/script_error.rb
         
     | 
| 
       109 
112 
     | 
    
         
             
            - lib/btcruby/script/script_flags.rb
         
     | 
| 
       110 
113 
     | 
    
         
             
            - lib/btcruby/script/script_interpreter.rb
         
     | 
| 
      
 114 
     | 
    
         
            +
            - lib/btcruby/script/script_interpreter_plugin.rb
         
     | 
| 
       111 
115 
     | 
    
         
             
            - lib/btcruby/script/script_number.rb
         
     | 
| 
       112 
116 
     | 
    
         
             
            - lib/btcruby/script/signature_checker.rb
         
     | 
| 
       113 
117 
     | 
    
         
             
            - lib/btcruby/script/signature_hashtype.rb
         
     | 
| 
       114 
118 
     | 
    
         
             
            - lib/btcruby/script/test_signature_checker.rb
         
     | 
| 
       115 
119 
     | 
    
         
             
            - lib/btcruby/script/transaction_signature_checker.rb
         
     | 
| 
      
 120 
     | 
    
         
            +
            - lib/btcruby/secp256k1.rb
         
     | 
| 
       116 
121 
     | 
    
         
             
            - lib/btcruby/transaction.rb
         
     | 
| 
       117 
122 
     | 
    
         
             
            - lib/btcruby/transaction_builder.rb
         
     | 
| 
       118 
123 
     | 
    
         
             
            - lib/btcruby/transaction_builder/errors.rb
         
     | 
| 
         @@ -120,8 +125,8 @@ files: 
     | 
|
| 
       120 
125 
     | 
    
         
             
            - lib/btcruby/transaction_builder/result.rb
         
     | 
| 
       121 
126 
     | 
    
         
             
            - lib/btcruby/transaction_builder/signer.rb
         
     | 
| 
       122 
127 
     | 
    
         
             
            - lib/btcruby/transaction_input.rb
         
     | 
| 
       123 
     | 
    
         
            -
            - lib/btcruby/transaction_outpoint.rb
         
     | 
| 
       124 
128 
     | 
    
         
             
            - lib/btcruby/transaction_output.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - lib/btcruby/validation.rb
         
     | 
| 
       125 
130 
     | 
    
         
             
            - lib/btcruby/version.rb
         
     | 
| 
       126 
131 
     | 
    
         
             
            - lib/btcruby/wif.rb
         
     | 
| 
       127 
132 
     | 
    
         
             
            - lib/btcruby/wire_format.rb
         
     | 
| 
         @@ -131,6 +136,10 @@ files: 
     | 
|
| 
       131 
136 
     | 
    
         
             
            - spec/block_header_spec.rb
         
     | 
| 
       132 
137 
     | 
    
         
             
            - spec/block_spec.rb
         
     | 
| 
       133 
138 
     | 
    
         
             
            - spec/currency_formatter_spec.rb
         
     | 
| 
      
 139 
     | 
    
         
            +
            - spec/data/script_invalid.rb
         
     | 
| 
      
 140 
     | 
    
         
            +
            - spec/data/script_valid.rb
         
     | 
| 
      
 141 
     | 
    
         
            +
            - spec/data/tx_invalid.rb
         
     | 
| 
      
 142 
     | 
    
         
            +
            - spec/data/tx_valid.rb
         
     | 
| 
       134 
143 
     | 
    
         
             
            - spec/data_spec.rb
         
     | 
| 
       135 
144 
     | 
    
         
             
            - spec/diagnostics_spec.rb
         
     | 
| 
       136 
145 
     | 
    
         
             
            - spec/key_spec.rb
         
     | 
| 
         @@ -145,7 +154,9 @@ files: 
     | 
|
| 
       145 
154 
     | 
    
         
             
            - spec/open_assets/asset_transaction_spec.rb
         
     | 
| 
       146 
155 
     | 
    
         
             
            - spec/open_assets/issuance_id_spec.rb
         
     | 
| 
       147 
156 
     | 
    
         
             
            - spec/proof_of_work_spec.rb
         
     | 
| 
      
 157 
     | 
    
         
            +
            - spec/script_interpreter_spec.rb
         
     | 
| 
       148 
158 
     | 
    
         
             
            - spec/script_spec.rb
         
     | 
| 
      
 159 
     | 
    
         
            +
            - spec/secp256k1_spec.rb
         
     | 
| 
       149 
160 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       150 
161 
     | 
    
         
             
            - spec/transaction_builder_spec.rb
         
     | 
| 
       151 
162 
     | 
    
         
             
            - spec/transaction_spec.rb
         
     | 
| 
         @@ -194,7 +205,9 @@ test_files: 
     | 
|
| 
       194 
205 
     | 
    
         
             
            - spec/open_assets/asset_transaction_spec.rb
         
     | 
| 
       195 
206 
     | 
    
         
             
            - spec/open_assets/issuance_id_spec.rb
         
     | 
| 
       196 
207 
     | 
    
         
             
            - spec/proof_of_work_spec.rb
         
     | 
| 
      
 208 
     | 
    
         
            +
            - spec/script_interpreter_spec.rb
         
     | 
| 
       197 
209 
     | 
    
         
             
            - spec/script_spec.rb
         
     | 
| 
      
 210 
     | 
    
         
            +
            - spec/secp256k1_spec.rb
         
     | 
| 
       198 
211 
     | 
    
         
             
            - spec/transaction_builder_spec.rb
         
     | 
| 
       199 
212 
     | 
    
         
             
            - spec/transaction_spec.rb
         
     | 
| 
       200 
213 
     | 
    
         
             
            - spec/wire_format_spec.rb
         
     |