spec/bitcoin/builder_spec.rb in bitcoin-ruby-0.0.5 vs spec/bitcoin/builder_spec.rb in bitcoin-ruby-0.0.6

- old
+ new

@@ -83,10 +83,33 @@ tx2.in[0].prev_out_index.should == tx.in[0].prev_out_index tx2.out[0].value.should == tx.out[0].value tx2.out[0].pk_script.should == tx.out[0].pk_script end + it "should allow txin.prev_out as tx or hash" do + prev_tx = @block.tx[0] + tx1 = build_tx do |t| + t.input {|i| i.prev_out prev_tx, 0 } + end + tx2 = build_tx do |t| + t.input {|i| i.prev_out prev_tx.hash, 0, prev_tx.out[0].pk_script } + end + tx1.in[0].should == tx2.in[0] + end + + + it "should provide txout#to shortcut" do + tx1 = build_tx do |t| + t.output {|o| o.value 123; o.to @keys[1].addr } + end + tx2 = build_tx do |t| + t.output {|o| o.value 123 + o.script {|s| s.recipient @keys[1].addr } } + end + tx1.out[0].should == tx2.out[0] + end + it "should build unsigned transactions and add the signature hash" do tx = build_tx do |t| t.input do |i| i.prev_out @block.tx[0] i.prev_out_index 0 @@ -100,10 +123,110 @@ tx.is_a?(Bitcoin::P::Tx).should == true tx.in[0].sig_hash.should != nil end + it "should build unsigned multisig transactions and add the signature hash" do + tx1 = build_tx do |t| + t.input {|i| i.prev_out(@block.tx[0], 0); i.signature_key(@keys[0]) } + t.output do |o| + o.value 123 + o.to [2, *@keys[0..2].map(&:pub)], :multisig + end + end + + tx2 = build_tx do |t| + t.input do |i| + i.prev_out tx1, 0 + i.signature_key @keys[0] + end + t.output {|o| o.value 123; o.to @keys[0].addr } + end + + tx2.is_a?(Bitcoin::P::Tx).should == true + tx2.in[0].sig_hash.should != nil + end + + it "should build unsigned p2sh multisig transactions and add the signature hash" do + tx1 = build_tx do |t| + t.input {|i| i.prev_out(@block.tx[0], 0); i.signature_key(@keys[0]) } + t.output do |o| + o.value 123 + o.to [2, *@keys[0..2].map(&:pub)], :p2sh_multisig + end + end + + tx2 = build_tx do |t| + t.input do |i| + i.prev_out tx1, 0 + i.signature_key @keys[0] + i.redeem_script tx1.out[0].redeem_script + end + t.output {|o| o.value 123; o.to @keys[0].addr } + end + + tx2.is_a?(Bitcoin::P::Tx).should == true + tx2.in[0].sig_hash.should != nil + end + + it "should add change output" do + change_address = Bitcoin::Key.generate.addr + tx = build_tx(input_value: @block.tx[0].out.map(&:value).inject(:+), + change_address: change_address) do |t| + t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @keys[0] } + t.output {|o| o.value 12345; o.script {|s| s.recipient @keys[1].addr } } + end + tx.out.count.should == 2 + tx.out.last.value.should == 50e8 - 12345 + Bitcoin::Script.new(tx.out.last.pk_script).get_address.should == change_address + end + + it "should add change output and leave fee" do + change_address = Bitcoin::Key.generate.addr + tx = build_tx(input_value: @block.tx[0].out.map(&:value).inject(:+), + change_address: change_address, leave_fee: true) do |t| + t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @keys[0] } + t.output {|o| o.value 12345; o.script {|s| s.recipient @keys[1].addr } } + end + tx.out.count.should == 2 + tx.out.last.value.should == 50e8 - 12345 - Bitcoin.network[:min_tx_fee] + Bitcoin::Script.new(tx.out.last.pk_script).get_address.should == change_address + + tx = build_tx(input_value: @block.tx[0].out.map(&:value).inject(:+), + change_address: change_address, leave_fee: true) do |t| + t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @keys[0] } + 49.times { t.output {|o| o.value 1e8; o.script {|s| s.recipient @keys[1].addr } } } + t.output {|o| o.value(1e8 - 10000); o.script {|s| s.recipient @keys[1].addr } } + end + tx.out.size.should == 50 + tx.out.map(&:value).inject(:+).should == 50e8 - 10000 + end + + it "randomize_outputs should not modify output values or fees" do + change_address = Bitcoin::Key.generate.addr + tx = build_tx(input_value: @block.tx[0].out.map(&:value).inject(:+), + change_address: change_address, leave_fee: true) do |t| + t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @keys[0] } + t.output {|o| o.value 12345; o.script {|s| s.recipient @keys[1].addr } } + t.randomize_outputs + end + + tx.out.count.should == 2 + tx.out.last.value.should == 50e8 - 12345 - Bitcoin.network[:min_tx_fee] + Bitcoin::Script.new(tx.out.last.pk_script).get_address.should == change_address + + tx = build_tx(input_value: @block.tx[0].out.map(&:value).inject(:+), + change_address: change_address, leave_fee: true) do |t| + t.input {|i| i.prev_out @block.tx[0]; i.prev_out_index 0; i.signature_key @keys[0] } + 49.times { t.output {|o| o.value 1e8; o.script {|s| s.recipient @keys[1].addr } } } + t.output {|o| o.value(1e8 - 10000); o.script {|s| s.recipient @keys[1].addr } } + t.randomize_outputs + end + tx.out.size.should == 50 + tx.out.map(&:value).inject(:+).should == 50e8 - 10000 + end + it "should build address script" do key = Bitcoin::Key.generate s = script {|s| s.type :address; s.recipient key.addr } Bitcoin::Script.new(s).to_string.should == "OP_DUP OP_HASH160 #{Bitcoin.hash160_from_address(key.addr)} OP_EQUALVERIFY OP_CHECKSIG" @@ -117,8 +240,62 @@ it "should build multisig script" do keys = 3.times.map { Bitcoin::Key.generate } s = script {|s| s.type :multisig; s.recipient 1, keys[0].pub, keys[1].pub } Bitcoin::Script.new(s).to_string.should == "1 #{keys[0].pub} #{keys[1].pub} 2 OP_CHECKMULTISIG" + end + + it "should build and spend multisig output" do + tx1 = build_tx do |t| + t.input {|i| i.prev_out(@block.tx[0], 0); i.signature_key(@keys[0]) } + t.output do |o| + o.value 123 + o.to [2, *@keys[0..2].map(&:pub)], :multisig + end + end + + Bitcoin::Script.new(tx1.out[0].pk_script).to_string.should == + "2 #{@keys[0..2].map(&:pub).join(' ')} 3 OP_CHECKMULTISIG" + + tx2 = build_tx do |t| + t.input do |i| + i.prev_out tx1, 0 + i.signature_key @keys[0..1] + end + t.output {|o| o.value 123; o.to @keys[0].addr } + end + + tx2.verify_input_signature(0, tx1).should == true + end + + it "should build and spend p2sh multisig output" do + tx1 = build_tx do |t| + t.input {|i| i.prev_out(@block.tx[0], 0); i.signature_key(@keys[0]) } + t.output do |o| + o.value 123 + o.to [2, *@keys[0..2].map(&:pub)], :p2sh_multisig + end + end + + Bitcoin::Script.new(tx1.out[0].pk_script).to_string.should == + "OP_HASH160 #{Bitcoin.hash160(tx1.out[0].redeem_script.hth)} OP_EQUAL" + + tx2 = build_tx do |t| + t.input do |i| + i.prev_out tx1, 0 + # provide 2 required keys for signing + i.signature_key @keys[0..1] + # provide the redeem script from the previous output + i.redeem_script tx1.out[0].redeem_script + end + + t.output {|o| o.value 123; o.to @keys[0].addr } + end + + script = Bitcoin::Script.new(tx2.in[0].script_sig, tx1.out[0].pk_script) + # check script execution is valid + script.run { true }.should == true + # check signatures are valid + tx2.verify_input_signature(0, tx1).should == true end end