美文网首页
2019-11-14

2019-11-14

作者: YANG_ad29 | 来源:发表于2019-11-14 12:14 被阅读0次

bitcion 离线签名
加入依赖

 <dependency>
          <groupId>org.bitcoinj</groupId>
          <artifactId>bitcoinj-core</artifactId>
          <version>0.14.7</version>
 </dependency>
//rpc
 <dependency>
          <groupId>com.github.briandilley.jsonrpc4j</groupId>
          <artifactId>jsonrpc4j</artifactId>
          <version>1.5.3</version>
</dependency>
//构建交易
public String create(String addrfrom, String addrto, BigDecimal amount,BigDecimal mbfee ){
//创建rpc 客户端
   BitcoinRpc client = new BitcoinRpc();
 List<BtcRpcUnspent> mBtcRpcUnspent = client.getListUnspent(6L,9999L,Arrays.asList(addrfrom));
//根据转账数量和交易费过滤utxo
.....
 NetworkParameters params  = MainNetParams.get();
 Transaction spendTx = new Transaction(params);
  Address address = Address.fromBase58(params, addrfrom);
  Address toaddress = Address.fromBase58(params, addrto);

//构建交易数据
        for (BtcRpcUnspent utxo : mBtcRpcUnspent)
        {
            String hash = utxo.getTransactionHash();
            int index = utxo.getN();
            Script scriptPubKey =ScriptBuilder.createOutputScript(address);
            Sha256Hash mHash =new Sha256Hash(hash);
            spendTx.addInput(mHash,index,scriptPubKey);
        }
//输出
 spendTx.addOutput(Coin.valueOf(amountValue), toaddress);
//找零
 spendTx.addOutput(toself, address);//toself 根据选择的utxo总额 减去 转出 减去交易费
 byte[] spendbyte=spendTx.bitcoinSerialize();
String spendstring = HEX.encode(spendbyte);
return spendstring ;
}

//bip44

   public static final ChildNumber ONE_HARDENED = new ChildNumber(1, true);
    public static final ChildNumber ZERO_HARDENED = new ChildNumber(0, true);
 public ECKey createBip44Address(List<String> mnemonicWords, String passPhrase,int number){
        byte[] seeded = MnemonicCode.toSeed(mnemonicWords, passPhrase);
        ChildNumber btcindex = checkNetStatus()?ZERO_HARDENED:ONE_HARDENED;
        DeterministicSeed seed = new DeterministicSeed(mnemonicWords, seeded, "", Utils.currentTimeSeconds());
        DeterministicKey rootPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed.getSeedBytes());
        DeterministicHierarchy deterministicHierarchy = new DeterministicHierarchy(rootPrivateKey);
        ImmutableList<ChildNumber> path = ImmutableList.of(new ChildNumber(44, true),btcindex, ChildNumber.ZERO_HARDENED);
        DeterministicKey fourpath = deterministicHierarchy.get(path, true, true);
        DeterministicKey fourpathhd = HDKeyDerivation.deriveChildKey(fourpath, 0);
        DeterministicKey fivepathhd = HDKeyDerivation.deriveChildKey(fourpathhd, number);
        ECKey ecKey = ECKey.fromPrivate(fivepathhd.getPrivKey());
       // Address address = ecKey.toAddress(params);
        return ecKey;
    }

//签名


    public String signTransaction(String inputTransaction, String addr, List<String> mnemonicWords, String passPhrase) {
//inputTransaction  为上面构建后序列化的未签名的交易
   byte[] bytes = HEX.decode(inputTransaction);
   Transaction transaction = new Transaction(params, bytes);
   ECKey ecKey=createBip44Address(List<String> mnemonicWords, String passPhrase,int number);
int numInputs = transaction.getInputs().size();
 for (int i = 0; i < numInputs; i++) {
            TransactionInput txIn = transaction.getInput(i);
            Address address = new Address(params, addr);
            Script scriptPubKey = ScriptBuilder.createOutputScript(address);

            byte[] pubKeyHash = scriptPubKey.getPubKeyHash();
            System.out.println("getWallet()===" + mWallet);
          
            if (ecKey == null) {
                loggor.error("签名失败 ecKey is null!!!");
                return "";
            }
    
            txIn.setScriptSig(scriptPubKey.createEmptyInputScript(ecKey, scriptPubKey));
            Script inputScript = txIn.getScriptSig();
            byte[] script = scriptPubKey.getProgram();  // 应该是byte类型的上笔交易的输出脚本
            try {
                TransactionSignature signature = transaction.calculateSignature(i, ecKey, script, Transaction.SigHash.ALL, false);
                int sigIndex = 0;
                inputScript = scriptPubKey.getScriptSigWithSignature(inputScript, signature.encodeToBitcoin(), sigIndex);
                txIn.setScriptSig(inputScript);
            } catch (ECKey.KeyIsEncryptedException e) {
                throw e;
            } catch (ECKey.MissingPrivateKeyException e) {
                System.out.println("ecKey===" + e);

            }
        }
 // 已签名的交易对象序列化
        byte[] spendBytes = transaction.bitcoinSerialize();
        String txid = transaction.getHashAsString();
        String signDataStr = HEX.encode(spendBytes);
       return signDataStr;//通过client.sendRawTransaction(signDataStr)就能发送交易了
}
@Data
public class BtcRpcUnspent {
    private int n;
    private String transactionHash;
    private String address;
    private String script;
    private double value;
    private long confirmations;
    private String account;

    public BtcRpcUnspent(int n, String transactionHash, String address, String script, double value, long confirmations,String account) {
        this.n = n;
        this.transactionHash = transactionHash;
        this.address = address;
        this.script = script;
        this.value = value;
        this.confirmations = confirmations;
        this.account = account;
    }

    public BtcRpcUnspent(JsonObject o) {
        this(   o.has("vout") ? o.get("vout").getAsInt() : -1,
                o.has("txid") ? o.get("txid").getAsString() :"",
                o.has("address") ? o.get("address").getAsString() :"",
                o.has("scriptPubKey") ? o.get("scriptPubKey").getAsString() :"",
                o.has("amount") ? o.get("amount").getAsDouble() : -1,
                o.has("confirmations") ? o.get("confirmations").getAsLong() : -1,
                o.has("account") ? o.get("account").getAsString() :""
        );
    }

}

在构建交易时 拿到UTXO后可以通过rpc来构建未签名的交易

 List<BtcListUnspent> btcListUnspents = btcListUnspents = client.getListUnspent(6L, 9999L, Arrays.asList(addrfrom));
//过滤
List<BtcCreateVin> inputs = new ArrayList<>();
                BigDecimal selectAmount = BigDecimal.ZERO;
                for (BtcListUnspent unspent : btcListUnspents) {
                    if (selectAmount.compareTo(amount.add(mbfee)) == -1) {
                        selectAmount = selectAmount.add(unspent.getAmount());
                        inputs.add(new BtcCreateVin(unspent.getTxid(), unspent.getVout()));
                    } else {
                        break;
                    }
                }

//输出
 HashMap<String, BigDecimal> outputs = new HashMap<>();
                outputs.put(addrfrom, uxtofrom);
                outputs.put(addrto, amount);

 String signHash = client.createrawtransaction(inputs, outputs);
return signHash ;
@Data
public class BtcListUnspent {

    //交易哈希
    private String txid;

    //位置
    private int vout;

    //地址
    private String address;

    //标签
    private String label;

    //公钥哈希
    private String scriptPubKey;

    //金额
    private BigDecimal amount;

    //确认数
    private long confirmations;

    //赎回脚本
    private String redeemScript;

    //隔离见证脚本
    private String witnessScript;

    //本地可花费
    private boolean spendable;

    private boolean solvable;

    private String desc;

    private boolean safe;
}
@Data
public class BtcVin {

    private String txid;

    private long vout;

    private List<String> txinwitness;

    private long sequence;

    private BtcScriptSig scriptSig;

}

//也可以拿到UTXO传到前端 由前端构建与签名(缺点是传输数据大)

public String createandsign(String addrfrom, String addrto, BigDecimal amount,BigDecimal mbfee , List<BtcListUnspent> btcListUnspents,List<String> words){
  Transaction transaction = new Transaction(params);
 ECKey ecKey = createBip44Address(words, "", number);
 transaction.addOutput(Coin.parseCoin(amount.toString()), Address.fromBase58(params, to));
 if (change.compareTo(BigDecimal.ZERO) > 0) {
            transaction.addOutput(Coin.parseCoin(change.toString()), Address.fromBase58(params, from));
        }
 for (BtcListUnspent btcListUnspent:btcListUnspents) {
            TransactionOutPoint transactionOutPoint = new TransactionOutPoint(params,btcListUnspent.getVout(), Sha256Hash.wrap(btcListUnspent.getTxid()));
          //  Script utxo_script = (new ScriptBuilder()).createOutputScript(ecKey.toAddress(params));
      Script utxo_script = (new Script(HEX.decode(btcListUnspent.getScriptPubKey()));
            transaction.addSignedInput(transactionOutPoint,utxo_script,ecKey);
        }
        byte[] spendBytes = transaction.bitcoinSerialize();
        String signDataStr = HEX.encode(spendBytes);
        BchRpc instance = BchRpc.getInstance();
        String s = instance.sendRawTransaction(signDataStr);
}

相关文章

  • 11月14日

    2019-11-14 毛雅亭 字数 636 · 阅读 1 2019-11-11 08:16 ...

  • 2019-11-14

    2019-11-14 【日精进打卡第 600 天 【知~学习】 《六项精进》大纲 4 遍共 2256 遍 《大学》...

  • 文先森的日常--剩32天

    日精进打卡第456天 姓名:李文杰 (四爷); 公司:中国太平人寿; 日期:2019-11-14 【知~学习】 《...

  • 如何高效解决问题

    标签:问题,生活问题,技术问题,减肥,收纳 修订历史 2019-11-14:首次发布。 如何有效解决生活问题 要想...

  • openstack学习笔记1

    2019-11-14 1.CPU 内核态 用户态 Ring0~Ring3 2.VMM virtual machin...

  • Don't take the shit! 想骗中国人,没门!-b

    2019-11-14第七天 越来越脱离worry,成为warrior,not really;瑜伽和佛教学习教会我们...

  • 2019年上海浦东“秋季国际大健康产业博览会”

    2019第九届上海国际大健康产业品牌博览会 展会时间: 2019-11-12 — 2019-11-14 展馆:上海...

  • 鉴峰丨冲突,直面它,永远都不要逃避冲突

    鉴峰自我管理 [连续签到第673天] 2019-11-14 周四 职场, 总会有冲突, 你我需要直面它, 永远不要...

  • 2019-11-14

    焦初16期 坚持分享第162天 2019-11-14(周四)晴 (摘)多少次, 难过、悲伤、生气, 是因为别人没有...

  • 2019-11-14

    2019-11-14 姓名:符振华(379期 反省三组) 公司:深圳蔚蓝时代商业管理有限公司-上海第一分公司 【日...

网友评论

      本文标题:2019-11-14

      本文链接:https://www.haomeiwen.com/subject/riilictx.html