- I have 3 parties sender, intermediary, and receiver.
- Intermediary and receiver send pubkey to sender.
- Sender get two public keys from other two users on the regtest network, they are hard coded into the program for test convenience.
- Sender forms a multisig transaction with the pubkey of the other two users, then broadcasts.
- Intermediary gets the transaction, signs it and sends its signature to receiver
- Receiver gets the sig of intermediary, signs the transaction with it's sig and intermediary's
- Then it shows money has been gotten
Problem
- let say I have 5btc in the sender wallet, I then send 1btc to the receiver. On the receiver side instead of 1btc being put in the wallet I get the 3.99btc (that is the receiver gets the balance of the sender after mining fees). It's rather a strange behavior.
- secondly it works sometimes the correct amount gets sent to the receiver but I am not able to send the amount.
Thank you for your anticipated help.
Please see my code below
//....relevant imports
public class Bitsender {
NetworkParameters params = RegTestParams.get();
WalletAppKit kit = new WalletAppKit(params, new File("."),"sender-wallet" );
public void startUp(){
System.out.println("Setting things up..");
kit.connectToLocalHost();
kit.startAsync();
kit.awaitRunning();
WalletListener wlistener = new WalletListener();
kit.wallet().addEventListener(wlistener);
}
private void receive() {
System.out.println("Feed me: " + kit.wallet().freshReceiveAddress().toString());
}
public void getBal(){
System.out.println("Sender Balance is " + kit.wallet().getBalance());
}
private void send(String address) throws AddressFormatException, InsufficientMoneyException {
//this are the byte rep of the two multisig keys
byte[] reckey = new byte[]{2,127,-81,126,111,23,-36,124,-79,-15,83,56,-52,18,58,-80,-100,-120,9,57,-98,99,-96,29,10,-19,-74,-84,-32,43,19,9,111};
byte[] intkey = new byte[]{3,-27,73,-95,-86,-98,70,-51,-34,99,53,8,-5,127,59,-22,-124,-76,-112,49,-62,61,-51,-42,107,88,-26,-100,-23,62,-118,-41,80};
//convert them to pubkyes
ECKey receiverkey = new ECKey(null, reckey);
ECKey intermediarykey = new ECKey(null, intkey);
//create a transaction
Transaction contract = new Transaction(params);
//form a list of keys to be added to multisig script
Listkeys = ImmutableList.of(receiverkey, intermediarykey);
//construct script with keys
Script script = ScriptBuilder.createMultiSigOutputScript(2, keys);
//set amount to be sent
Coin amount = Coin.parseCoin("10");//.valueOf(0, 80);
//form an output and add the amount and script
contract.addOutput(amount, script);
System.out.println("Value to be sent " +contract.getOutput(0).getValue());
//adding input to the transaction from the wallet
Wallet.SendRequest req = Wallet.SendRequest.forTx(contract);
kit.wallet().completeTx(req);
kit.wallet().signTransaction(req);
//kit.wallet().sendCoins(req);
String sscript = new Gson().toJson(script);
System.out.println("Script for this transaction is-----" + "\n" + sscript);
System.out.println("End of script");
byte[] trx = contract.bitcoinSerialize();
String strx = new Gson().toJson(trx);
System.out.println("Transaction is-----" + "\n" + strx);
System.out.println("End of transaction");
kit.peerGroup().broadcastTransaction(req.tx);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, AddressFormatException, InsufficientMoneyException {
System.out.println("Sender Client");
String userInput = "";
Bitsender sender = new Bitsender();
sender.startUp();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!"quit".equals(userInput = in.readLine())) {
if(userInput.equals("receive")){
sender.receive();
}
else if(userInput.equals("bal")){
sender.getBal();
}
else if(userInput.equals("send")){
//get the address of the bitreceiver
sender.send(userInput);
//sender.send(userInput.split(" ")[1]);
}
}
}
}
//...relevant imports
public class Bitreceiver {
NetworkParameters params = RegTestParams.get();
WalletAppKit kit = new WalletAppKit(params, new File("."),"receiver-wallet" );
public void startUp(){
System.out.println("Setting things up..");
//kit.connectToLocalHost();
kit.startAsync();
kit.awaitRunning();
WalletListener wlistener = new WalletListener();
kit.wallet().addEventListener(wlistener);
}
public void getBal(){
System.out.println("Balance is " + kit.wallet().getBalance());
}
private void receive() {
//System.out.println("Feed me: " + kit.wallet().getActiveKeychain().getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).toAddress(params));
ECKey key = kit.wallet().freshReceiveKey();//.freshReceiveAddress();
Address addr = key.toAddress(params);
byte[] pubkey = key.getPubKey();
String spk = new Gson().toJson(pubkey);
System.out.println("Feed me address: " + addr.toString());
System.out.println("Feed me public key: " + spk);
}
private void claim(){
//System.out.println(kit.wallet().getWalletTransactions().toString());
byte[] reckey = new byte[]{2,127,-81,126,111,23,-36,124,-79,-15,83,56,-52,18,58,-80,-100,-120,9,57,-98,99,-96,29,10,-19,-74,-84,-32,43,19,9,111};
byte[] intkey = new byte[]{3,-27,73,-95,-86,-98,70,-51,-34,99,53,8,-5,127,59,-22,-124,-76,-112,49,-62,61,-51,-42,107,88,-26,-100,-23,62,-118,-41,80};
String sint = "{\"r\":95659142858888513941404554021932981678862401841800158047860591604698882661844,\"s\":44245425850115539565526070211043699757053575051384836017709636920266660223817}";
ECKey.ECDSASignature intsig = new Gson().fromJson(sint, ECKey.ECDSASignature.class);
ECKey receiverkey = kit.wallet().getActiveKeychain().findKeyFromPubKey(reckey);
byte[] contractbyte = new byte[]{1,0,0,0,1,-65,50,31,-50,1,92,17,17,116,-30,-68,80,43,-114,-56,89,116,-58,-65,-46,-111,6,-102,-43,-69,82,41,-46,7,-6,-94,75,1,0,0,0,106,71,48,68,2,32,70,5,-15,48,-90,-94,-56,-21,90,-23,97,65,106,-86,52,-101,-39,34,45,-103,75,35,123,65,4,-64,24,97,-47,-55,-95,50,2,32,10,48,-59,-72,31,-17,49,-104,-12,-115,96,109,-18,78,82,80,5,-105,33,94,83,51,-41,41,-124,-80,-76,-40,11,-35,0,59,1,33,3,-121,-54,-90,-3,-49,-25,21,-89,4,-19,111,-125,-12,-76,4,71,90,-117,-102,92,104,-103,109,-98,3,-49,100,23,125,102,-54,-120,-1,-1,-1,-1,2,0,-54,-102,59,0,0,0,0,71,82,33,2,127,-81,126,111,23,-36,124,-79,-15,83,56,-52,18,58,-80,-100,-120,9,57,-98,99,-96,29,10,-19,-74,-84,-32,43,19,9,111,33,3,-27,73,-95,-86,-98,70,-51,-34,99,53,8,-5,127,59,-22,-124,-76,-112,49,-62,61,-51,-42,107,88,-26,-100,-23,62,-118,-41,80,82,-82,96,85,-51,29,0,0,0,0,25,118,-87,20,-24,119,-65,42,-114,-21,-75,-74,-64,83,-94,31,-104,-33,-59,47,9,42,112,-95,-120,-84,0,0,0,0};
Transaction contract = new Transaction(params, contractbyte);
contract.verify();
TransactionOutput multisigOutput = contract.getOutput(1);
Script multisigScript = multisigOutput.getScriptPubKey();
Coin value = multisigOutput.getValue();
//byte[] contractbyte = new byte[]{1,0,0,0,1,75,-53,74,65,97,96,55,-110,-23,-44,-84,93,-111,-92,-107,-110,116,7,-88,32,90,-73,110,116,-2,25,-125,8,-52,-75,58,74,1,0,0,0,107,72,48,69,2,33,0,-31,-42,-97,41,115,46,-62,-78,116,80,100,17,0,121,-9,13,72,-67,9,28,72,75,-7,27,-7,-90,95,10,-11,8,-25,104,2,32,118,-15,48,-79,80,-83,-33,-115,-45,115,101,-42,105,39,96,-91,73,-2,44,51,-116,12,111,120,-104,-80,-44,97,108,62,-91,68,1,33,3,-88,94,-90,38,-41,-54,56,127,83,-118,7,15,112,98,84,-58,109,-100,-111,-90,23,-109,50,23,-108,85,-75,30,19,99,-110,-57,-1,-1,-1,-1,2,-104,-115,-46,-19,0,0,0,0,25,118,-87,20,101,93,-123,-49,-47,-23,2,-92,-22,-91,51,-49,-23,52,101,-28,-85,-13,-46,-18,-120,-84,-128,-106,-104,0,0,0,0,0,71,82,33,2,41,20,-11,-125,93,119,-120,69,101,101,11,-13,114,13,9,33,-103,-84,-127,-30,67,-74,42,-124,-120,109,33,-48,-128,27,-116,-86,33,2,-89,-31,-23,-13,-52,-51,48,-28,-45,13,-90,-105,49,104,-112,-10,-128,-72,-34,12,19,47,-9,-54,-11,98,-100,126,-21,44,38,109,82,-82,0,0,0,0};
System.out.println("Value sent " + value.value);
Transaction spendtx = new Transaction(params);
spendtx.addOutput(value, receiverkey);
TransactionInput input = spendtx.addInput(multisigOutput);
Sha256Hash sighash = spendtx.hashForSignature(0, multisigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature recsig = receiverkey.sign(sighash);
//ECKey.ECDSASignature.decodeFromDER();
//Listkeys = ImmutableList.of(recsig, intsig);
TransactionSignature tsrecsig = new TransactionSignature(recsig, Transaction.SigHash.ALL, false);
TransactionSignature tsintsig = new TransactionSignature(intsig, Transaction.SigHash.ALL, false);
Script inputScript = ScriptBuilder.createMultiSigInputScript(ImmutableList.of(tsrecsig, tsintsig));
input.setScriptSig(inputScript);
System.out.println(new Gson().toJson(multisigScript.toString()));
//System.out.println(multisigOutput.getValue());
//input.verify(multisigOutput);
kit.peerGroup().broadcastTransaction(spendtx);
System.out.println(kit.wallet().getBalance());
kit.wallet().allowSpendingUnconfirmedTransactions();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, AddressFormatException, InsufficientMoneyException {
System.out.println("Receiver Client");
String userInput = "";
Bitreceiver receiver = new Bitreceiver();
receiver.startUp();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!"quit".equals(userInput = in.readLine())) {
if(userInput.equals("bal")){
receiver.getBal();
}
else if(userInput.equals("receive")){
receiver.receive();
}
else if(userInput.equals("claim")){
receiver.claim();
}
else if(userInput.equals("send")){
receiver.send();
}
}
}
}
//..relevant imports
public class Bitintermediary {
NetworkParameters params = RegTestParams.get();
WalletAppKit kit = new WalletAppKit(params, new File("."),"intermediarywallet" );
public void startUp(){
System.out.println("Setting things up..");
//kit.connectToLocalHost();
kit.startAsync();
kit.awaitRunning();
WalletListener wlistener = new WalletListener();
kit.wallet().addEventListener(wlistener);
//System.out.println("Send me money on: " + kit.wallet().freshReceiveAddress().toString());
}
private void receive() {
// System.out.println("Feed me: " + kit.wallet().freshReceiveAddress().toString());
ECKey key = kit.wallet().freshReceiveKey();//.freshReceiveAddress();
Address addr = key.toAddress(params);
byte[] pubkey = key.getPubKey();
String spk = new Gson().toJson(pubkey);
System.out.println("Feed me address: " + addr.toString());
System.out.println("Feed me public key: " + spk);
}
public void getBal(){
System.out.println("Balance is " + kit.wallet().getBalance());
}
private void send(String address) throws AddressFormatException, InsufficientMoneyException {
//Address to = Address.fromBase58(params, address);
Address to = new Address(params, address);
Coin value = Coin.parseCoin("10.00");
kit.wallet().sendCoins(kit.peerGroup(), to, value);
System.out.println("Sending some coins to: " + address);
}
private void claim(){
byte[] reckey = new byte[]{2,127,-81,126,111,23,-36,124,-79,-15,83,56,-52,18,58,-80,-100,-120,9,57,-98,99,-96,29,10,-19,-74,-84,-32,43,19,9,111};
byte[] intkey = new byte[]{3,-27,73,-95,-86,-98,70,-51,-34,99,53,8,-5,127,59,-22,-124,-76,-112,49,-62,61,-51,-42,107,88,-26,-100,-23,62,-118,-41,80};
ECKey interkey = kit.wallet().getActiveKeychain().findKeyFromPubKey(intkey);//new ECKey(null, intkey);
ECKey receiverkey = new ECKey(null, reckey);
//ECKey jm = kit.wallet().isPubKeyMine(intkey);//.getActiveKeychain().findKeyFromPubKey(intkey);
//kit.wallet().
//System.out.println(kit.wallet().isPubKeyMine(intkey));
System.out.println("Here \n" + kit.wallet().getActiveKeychain().findKeyFromPubKey(intkey).getPrivKey());
//ECKey key = new ECKey();
// System.out.println(interkey.getPrivKey());
byte[] contractbyte = new byte[]{1,0,0,0,1,-65,50,31,-50,1,92,17,17,116,-30,-68,80,43,-114,-56,89,116,-58,-65,-46,-111,6,-102,-43,-69,82,41,-46,7,-6,-94,75,1,0,0,0,106,71,48,68,2,32,70,5,-15,48,-90,-94,-56,-21,90,-23,97,65,106,-86,52,-101,-39,34,45,-103,75,35,123,65,4,-64,24,97,-47,-55,-95,50,2,32,10,48,-59,-72,31,-17,49,-104,-12,-115,96,109,-18,78,82,80,5,-105,33,94,83,51,-41,41,-124,-80,-76,-40,11,-35,0,59,1,33,3,-121,-54,-90,-3,-49,-25,21,-89,4,-19,111,-125,-12,-76,4,71,90,-117,-102,92,104,-103,109,-98,3,-49,100,23,125,102,-54,-120,-1,-1,-1,-1,2,0,-54,-102,59,0,0,0,0,71,82,33,2,127,-81,126,111,23,-36,124,-79,-15,83,56,-52,18,58,-80,-100,-120,9,57,-98,99,-96,29,10,-19,-74,-84,-32,43,19,9,111,33,3,-27,73,-95,-86,-98,70,-51,-34,99,53,8,-5,127,59,-22,-124,-76,-112,49,-62,61,-51,-42,107,88,-26,-100,-23,62,-118,-41,80,82,-82,96,85,-51,29,0,0,0,0,25,118,-87,20,-24,119,-65,42,-114,-21,-75,-74,-64,83,-94,31,-104,-33,-59,47,9,42,112,-95,-120,-84,0,0,0,0};
Transaction contract = new Transaction(params, contractbyte);
contract.verify();
TransactionOutput multisigOutput = contract.getOutput(1);
Script multisigScript = multisigOutput.getScriptPubKey();
//is the output what we expected
//checkState(multisigScript.isSentToMultiSig());
Coin value = multisigOutput.getValue();
System.out.println("Value sent " + value.value);
Transaction spendtx = new Transaction(params);
spendtx.addOutput(value, receiverkey);
spendtx.addInput(multisigOutput);
//sign and send sig to receiver to claim
Sha256Hash sighash = spendtx.hashForSignature(0, multisigScript, Transaction.SigHash.ALL, false);
ECKey.ECDSASignature signature = interkey.sign(sighash);
System.out.println(signature.toString());
String sig = new Gson().toJson(signature);
System.out.println("Signature of intermediary is:\n" + sig);
System.out.println("End of sig");
}
public static void main(String[] args) throws IOException, AddressFormatException, InsufficientMoneyException {
System.out.println("Intermediary Client");
String userInput = "";
Bitintermediary inter = new Bitintermediary();
inter.startUp();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!"quit".equals(userInput = in.readLine())) {
if(userInput.equals("receive")){
inter.receive();
}
else if(userInput.equals("bal")){
inter.getBal();
}
else if(userInput.equals("claim")){
inter.claim();
}
}
}
}