Esempio n. 1
0
 public function handle_order_tx_submission($order, $incoming_tx, $user_bip32_key)
 {
     $this->CI->load->model('transaction_cache_model');
     $currently_unsigned = strlen($order['partially_signed_transaction']) == 0;
     if ($currently_unsigned) {
         $start_tx = trim($order['unsigned_transaction']);
     } else {
         $start_tx = trim($order['partially_signed_transaction']);
     }
     $json = str_replace("'", '', $order['json_inputs']);
     $decode_current_tx = \BitWasp\BitcoinLib\RawTransaction::decode($start_tx);
     $decode_incoming_tx = \BitWasp\BitcoinLib\RawTransaction::decode($incoming_tx);
     // Does incoming tx match expected spend?
     $check = $this->CI->transaction_cache_model->check_if_expected_spend($decode_incoming_tx['vout'], $order['id']);
     if ($check !== $order['address']) {
         return 'Invalid transaction.';
     }
     // General check that signatures match tx
     $validate = \BitWasp\BitcoinLib\RawTransaction::validate_signed_transaction($incoming_tx, $json);
     if ($validate == FALSE) {
         return 'Invalid signature.';
     }
     $decode_redeem_script = \BitWasp\BitcoinLib\RawTransaction::decode_redeem_script($order['redeemScript']);
     if (!$currently_unsigned and $user_bip32_key['provider'] == 'JS') {
         // Need to build the sig from this tx into the last.
         $copy = $decode_incoming_tx;
         foreach ($copy['vin'] as $i => &$input) {
             $script = explode(" ", $input['scriptSig']['asm']);
             $sig1 = \BitWasp\BitcoinLib\RawTransaction::_encode_vint(strlen($script[1]) / 2) . $script[1];
             $old_script = explode(" ", $decode_current_tx['vin'][$i]['scriptSig']['asm']);
             $sig2 = \BitWasp\BitcoinLib\RawTransaction::_encode_vint(strlen($old_script[1]) / 2) . $old_script[1];
             $redeem_script = '4c' . \BitWasp\BitcoinLib\RawTransaction::_encode_vint(strlen($order['redeemScript']) / 2) . $order['redeemScript'];
             $input['scriptSig']['hex'] = '00' . $sig1 . $sig2 . $redeem_script;
         }
         $incoming_tx = \BitWasp\BitcoinLib\RawTransaction::encode($copy);
         // Now need to reorder sigs!
         $assoc = $this->associate_sigs_with_keys($incoming_tx, $json, $this->CI->bw_config->currencies[0]['crypto_magic_byte']);
         foreach ($copy['vin'] as $i => &$input) {
             $input['scriptSig']['hex'] = \BitWasp\BitcoinLib\RawTransaction::_apply_sig_scripthash_multisig($assoc[$i], array('public_keys' => $decode_redeem_script['keys'], 'script' => $order['redeemScript']));
         }
         $incoming_tx = \BitWasp\BitcoinLib\RawTransaction::encode($copy);
         $decode_incoming_tx = \BitWasp\BitcoinLib\RawTransaction::decode($incoming_tx);
     }
     // Compare signatures!
     $old_sig_map = $this->associate_sigs_with_keys($start_tx, $json, $this->CI->bw_config->currencies[0]['crypto_magic_byte']);
     // Now check current signatures against users key. submittee must have signed.
     $key_sig_map = $this->associate_sigs_with_keys($incoming_tx, $json, $this->CI->bw_config->currencies[0]['crypto_magic_byte']);
     foreach ($key_sig_map as $i => $input_sig_map) {
         // If the number of sigs hasn't increased, or no sig from the current user exists..
         if (count($old_sig_map) > 0 && count($input_sig_map) <= count($old_sig_map[$i]) or !isset($input_sig_map[$user_bip32_key['public_key']])) {
             return 'Incorrect signature!';
         }
     }
     // Broadcast tx if fully signed!
     if (!$currently_unsigned) {
         $this->CI->transaction_cache_model->to_broadcast($incoming_tx);
         $this->sendrawtransaction($incoming_tx);
     }
     return TRUE;
 }
 public function testTxDecodeNonStandard()
 {
     $txId = "e0c354620324422f59c9d62464a62240879cfb63856ebc60601da051522865ed";
     $raw = "0000000001e58a2b3e662984ec5a26c9d3bfbeab17c8bcb144d7b841ca2779b43f57424e23010000006b48304502210097166be10ed2660070929b68ea975e60ba4701bd5dbc2eb53290ce9ab6e5f9c502200222033604f63a4a7f97a29cd2039e97b4f9407544ced5ea6ec6371a223f2e98012103619344fbff8e9e203909cf9912c699f9d7ede4f3aa18b7545bfae16dd4c6df2effffffff020000000000000000216a1f4343484e01017b226d223a22746c222c2264223a7b2263223a223f63227d7d4847f50200000000226d784b4e7a3667583675627253457872326b66387556614539396d7a43536d78756900000000";
     $tx = RawTransaction::decode($raw);
     $this->assertEquals($raw, RawTransaction::encode($tx));
     $this->assertEquals($txId, RawTransaction::txid_from_raw(RawTransaction::encode($tx)));
 }
 /**
  * Create Spend Transaction
  *
  * This function takes a $from_address, an order address, and a $tx_outs array,
  * specifying who the transaction should pay.
  *
  * Returns TRUE if the transaction is successfully created, and previous details
  * removed, or else a string containing an error if it fails.
  *
  * @param string $from_address
  * @param array $tx_outs
  * @param string $script
  * @return bool|string
  */
 public function create_spend_transaction($from_address, array $tx_outs = array(), $script)
 {
     if (count($tx_outs) < 1) {
         return 'No outputs specified in transaction.';
     }
     $this->load->model('transaction_cache_model');
     // Add the inputs at the multisig address.
     $payments = $this->transaction_cache_model->payments_to_address($from_address);
     if (count($payments) == 0) {
         return 'No spendable outputs found for this address';
     }
     $order_id = $payments[0]['order_id'];
     // Create the transaction inputs
     $tx_ins = array();
     $tx_pkScripts = array();
     foreach ($payments as $pmt) {
         $tx_ins[] = array('txid' => $pmt['tx_id'], 'vout' => $pmt['vout']);
         $tx_pkScripts[] = array('txid' => $pmt['tx_id'], 'vout' => (int) $pmt['vout'], 'scriptPubKey' => $pmt['pkScript'], 'redeemScript' => $script);
     }
     $json = json_encode($tx_pkScripts);
     $tx_outs = array_map('strval', $tx_outs);
     $raw_transaction = RawTransaction::create($tx_ins, $tx_outs);
     if ($raw_transaction == FALSE) {
         return 'An error occurred creating the transaction!';
     } else {
         // Embed redeem script into all tx's
         $new_tx = RawTransaction::decode($raw_transaction);
         foreach ($new_tx['vin'] as &$input_ref) {
             //$empty_input = $script;
             $input_ref['scriptSig']['hex'] = $script;
         }
         $raw_transaction = RawTransaction::encode($new_tx);
         $decoded_transaction = RawTransaction::decode($raw_transaction);
         if ($this->update_order($order_id, array('unsigned_transaction' => $raw_transaction . " ", 'json_inputs' => "'{$json}'", 'partially_signed_transaction' => '', 'partially_signed_time' => '', 'partially_signing_user_id' => ''))) {
             $this->transaction_cache_model->clear_expected_for_address($from_address);
             $this->transaction_cache_model->log_transaction($decoded_transaction['vout'], $from_address, $order_id);
             return TRUE;
         }
         return 'An error occured updating the order!';
     }
 }