转 | JAVA版本区块链钱包核心代码

JAVA版本区块链钱包核心代码

attachments-2018-03-9MDlTgOS5aa74ab46b850.png

作者:微先锋

来源:博客园

原文链接:https://www.cnblogs.com/vxianfeng/p/9742166.html

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


Block.java

package com.ppblock.blockchain.core;

import java.io.Serializable;

/**

  • 区块

  • @author yangjian

  • @since 18-4-6 */ public class Block implements Serializable {

    /**

    • 区块 Header / private BlockHeader header; /*
    • 区块 Body */ private BlockBody body;

    public Block(BlockHeader header, BlockBody body) { this.header = header; this.body = body; }

    public Block() { }

    public BlockHeader getHeader() { return header; }

    public void setHeader(BlockHeader header) { this.header = header; }

    public BlockBody getBody() { return body; }

    public void setBody(BlockBody body) { this.body = body; }

    @Override public String toString() { return "Block{" + "header=" + header + ", body=" + body.toString() + '}'; } }

BlockBody.java

package com.ppblock.blockchain.core;

import java.io.Serializable; import java.util.ArrayList; import java.util.List;

/**

  • 区块数据

  • @author yangjian

  • @since 18-4-8 */ public class BlockBody implements Serializable {

    /**

    • 区块所包含的交易记录 */ private List<Transaction> transactions;

    public BlockBody(List<Transaction> transactions) { this.transactions = transactions; }

    public BlockBody() { this.transactions = new ArrayList<>(); }

    public List<Transaction> getTransactions() { return transactions; }

    public void setTransactions(List<Transaction> transactions) { this.transactions = transactions; }

    /**

    • 追加一笔交易
    • @param transaction */ public void addTransaction(Transaction transaction) { transactions.add(transaction); }

    @Override public String toString() { return "BlockBody{" + "transactions=" + transactions + '}'; } }

BlockChain.java

package com.ppblock.blockchain.core;

import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.ppblock.blockchain.crypto.Credentials; import com.ppblock.blockchain.crypto.Keys; import com.ppblock.blockchain.crypto.Sign; import com.ppblock.blockchain.db.DBAccess; import com.ppblock.blockchain.enums.TransactionStatusEnum; import com.ppblock.blockchain.event.MineBlockEvent; import com.ppblock.blockchain.event.SendTransactionEvent; import com.ppblock.blockchain.mine.Miner; import com.ppblock.blockchain.net.ApplicationContextProvider; import com.ppblock.blockchain.net.base.Node; import com.ppblock.blockchain.net.client.AppClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;

import java.math.BigDecimal;

/**

  • 区块链主类

  • @author yangjian

  • @since 18-4-6 */ @Component public class BlockChain {

    private static Logger logger = LoggerFactory.getLogger(BlockChain.class);

    @Autowired private DBAccess dbAccess;

    @Autowired private AppClient appClient;

    @Autowired private Miner miner;

    @Autowired private TransactionPool transactionPool;

    @Autowired private TransactionExecutor executor; /**

    • 挖取一个区块

    • @return */ public Block mining() throws Exception {

      Optional<Block> lastBlock = getLastBlock(); Block block = miner.newBlock(lastBlock); transactionPool.getTransactions().forEach(e -> block.getBody().addTransaction(e)); executor.run(block); //清空交易池 transactionPool.clearTransactions(); //存储区块 dbAccess.putLastBlockIndex(block.getHeader().getIndex()); dbAccess.putBlock(block); logger.info("Find a New Block, {}", block);

      //触发挖矿事件,并等待其他节点确认区块 ApplicationContextProvider.publishEvent(new MineBlockEvent(block)); return block; }

    /**

    • 发送交易

    • @param credentials 交易发起者的凭证

    • @param to 交易接收者

    • @param amount

    • @param data 交易附言

    • @return

    • @throws Exception */ public Transaction sendTransaction(Credentials credentials, String to, BigDecimal amount, String data) throws Exception {

      //校验付款和收款地址 Preconditions.checkArgument(to.startsWith("0x"), "收款地址格式不正确"); Preconditions.checkArgument(!credentials.getAddress().equals(to), "收款地址不能和发送地址相同");

      //构建交易对象 Transaction transaction = new Transaction(credentials.getAddress(), to, amount); transaction.setPublicKey(Keys.publicKeyEncode(credentials.getEcKeyPair().getPublicKey().getEncoded())); transaction.setStatus(TransactionStatusEnum.APPENDING); transaction.setData(data); transaction.setTxHash(transaction.hash()); //签名 String sign = Sign.sign(credentials.getEcKeyPair().getPrivateKey(), transaction.toString()); transaction.setSign(sign);

      //先验证私钥是否正确 if (!Sign.verify(credentials.getEcKeyPair().getPublicKey(), sign, transaction.toString())) { throw new RuntimeException("私钥签名验证失败,非法的私钥"); }

      //打包数据到交易池 transactionPool.addTransaction(transaction);

      //触发交易事件,向全网广播交易,并等待确认 ApplicationContextProvider.publishEvent(new SendTransactionEvent(transaction)); return transaction; }

    /**

    • 获取最后一个区块
    • @return */ public Optional<Block> getLastBlock() { return dbAccess.getLastBlock(); }

    /**

    • 添加一个节点

    • @param ip

    • @param port

    • @return */ public void addNode(String ip, int port) throws Exception {

      appClient.addNode(ip, port); Node node = new Node(ip, port); dbAccess.addNode(node); } }

BlockHeader.java

package com.ppblock.blockchain.core;

import com.ppblock.blockchain.crypto.Hash;

import java.io.Serializable; import java.math.BigInteger;

/**

  • 区块头

  • @author yangjian

  • @since 18-4-6 */ public class BlockHeader implements Serializable {

    /**

    • 区块高度 / private Integer index; /*
    • 难度指标 / private BigInteger difficulty; /*
    • PoW 问题的答案 / private Long nonce; /*
    • 时间戳 / private Long timestamp; /*
    • 区块 Hash / private String hash; /*
    • 上一个区块的 hash 地址 */ private String previousHash;

    public BlockHeader(Integer index, String previousHash) { this.index = index; this.timestamp = System.currentTimeMillis(); this.previousHash = previousHash; }

    public BlockHeader() { this.timestamp = System.currentTimeMillis(); }

    public Integer getIndex() { return index; }

    public void setIndex(Integer index) { this.index = index; }

    public BigInteger getDifficulty() { return difficulty; }

    public void setDifficulty(BigInteger difficulty) { this.difficulty = difficulty; }

    public Long getNonce() { return nonce; }

    public void setNonce(Long nonce) { this.nonce = nonce; }

    public Long getTimestamp() { return timestamp; }

    public void setTimestamp(Long timestamp) { this.timestamp = timestamp; }

    public String getPreviousHash() { return previousHash; }

    public void setPreviousHash(String previousHash) { this.previousHash = previousHash; }

    public String getHash() { return hash; }

    public void setHash(String hash) { this.hash = hash; }

    @Override public String toString() { return "BlockHeader{" + "index=" + index + ", difficulty=" + difficulty + ", nonce=" + nonce + ", timestamp=" + timestamp + ", hash='" + hash + ''' + ", previousHash='" + previousHash + ''' + '}'; }

    /**

    • 获取区块头的 hash 值
    • @return */ public String hash() { return Hash.sha3("BlockHeader{" + "index=" + index + ", difficulty=" + difficulty + ", nonce=" + nonce + ", timestamp=" + timestamp + ", previousHash='" + previousHash + ''' + '}'); } }

Transaction.java

package com.ppblock.blockchain.core;

import com.ppblock.blockchain.crypto.Hash; import com.ppblock.blockchain.enums.TransactionStatusEnum;

import java.math.BigDecimal;

/**

  • 交易对象

  • @author yangjian

  • @since 18-4-6 */ public class Transaction {

    /**

    • 付款人地址 / private String from; /*
    • 付款人签名 / private String sign; /*
    • 收款人地址 / private String to; /*
    • 收款人公钥 / private String publicKey; /*
    • 交易金额 / private BigDecimal amount; /*
    • 交易时间戳 / private Long timestamp; /*
    • 交易 Hash 值 / private String txHash; /*
    • 交易状态 / private TransactionStatusEnum status = TransactionStatusEnum.SUCCESS; /*
    • 交易错误信息 / private String errorMessage; /*
    • 附加数据 */ private String data;

    public Transaction(String from, String to, BigDecimal amount) { this.from = from; this.to = to; this.amount = amount; this.timestamp = System.currentTimeMillis(); }

    public Transaction() { this.timestamp = System.currentTimeMillis(); }

    public String getFrom() { return from; }

    public void setFrom(String from) { this.from = from; }

    public String getSign() { return sign; }

    public void setSign(String sign) { this.sign = sign; }

    public String getTo() { return to; }

    public void setTo(String to) { this.to = to; }

    public String getPublicKey() { return publicKey; }

    public void setPublicKey(String publicKey) { this.publicKey = publicKey; }

    public BigDecimal getAmount() { return amount; }

    public void setAmount(BigDecimal amount) { this.amount = amount; }

    public Long getTimestamp() { return timestamp; }

    public void setTimestamp(Long timestamp) { this.timestamp = timestamp; }

    public String getTxHash() { return txHash; }

    public void setTxHash(String txHash) { this.txHash = txHash; }

    public TransactionStatusEnum getStatus() { return status; }

    public void setStatus(TransactionStatusEnum status) { this.status = status; }

    public String getErrorMessage() { return errorMessage; }

    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }

    public String getData() { return data; }

    public void setData(String data) { this.data = data; }

    /**

    • 计算交易信息的Hash值
    • @return */ public String hash() { return Hash.sha3(this.toString()); }

    @Override public String toString() { return "Transaction{" + "from='" + from + ''' + ", to='" + to + ''' + ", publicKey=" + publicKey + ", amount=" + amount + ", timestamp=" + timestamp + ", data='" + data + ''' + '}'; } }

TransactionExecutor.java

package com.ppblock.blockchain.core;

import com.google.common.base.Optional; import com.ppblock.blockchain.account.Account; import com.ppblock.blockchain.crypto.Keys; import com.ppblock.blockchain.crypto.Sign; import com.ppblock.blockchain.db.DBAccess; import com.ppblock.blockchain.enums.TransactionStatusEnum; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;

import java.math.BigDecimal;

/**

  • 交易执行器

  • @author yangjian

  • @since 18-4-23 */ @Component public class TransactionExecutor {

    @Autowired private DBAccess dbAccess;

    @Autowired private TransactionPool transactionPool;

    /**

    • 执行区块中的交易

    • @param block */ public void run(Block block) throws Exception {

      for (Transaction transaction : block.getBody().getTransactions()) { synchronized (this) {

      Optional<Account> recipient = dbAccess.getAccount(transaction.getTo());
           //如果收款地址账户不存在,则创建一个新账户
           if (!recipient.isPresent()) {
               recipient = Optional.of(new Account(transaction.getTo(), BigDecimal.ZERO));
           }
           //挖矿奖励
           if (null == transaction.getFrom()) {
               recipient.get().setBalance(recipient.get().getBalance().add(transaction.getAmount()));
               dbAccess.putAccount(recipient.get());
               continue;
           }
           //账户转账
           Optional<Account> sender = dbAccess.getAccount(transaction.getFrom());
           //验证签名
           boolean verify = Sign.verify(
                   Keys.publicKeyDecode(transaction.getPublicKey()),
                   transaction.getSign(),
                   transaction.toString());
           if (!verify) {
               transaction.setStatus(TransactionStatusEnum.FAIL);
               transaction.setErrorMessage("交易签名错误");
               continue;
           }
           //验证账户余额
           if (sender.get().getBalance().compareTo(transaction.getAmount()) == -1) {
               transaction.setStatus(TransactionStatusEnum.FAIL);
               transaction.setErrorMessage("账户余额不足");
               continue;
           }
      
           //执行转账操作,更新账户余额
           sender.get().setBalance(sender.get().getBalance().subtract(transaction.getAmount()));
           recipient.get().setBalance(recipient.get().getBalance().add(transaction.getAmount()));
           dbAccess.putAccount(sender.get());
           dbAccess.putAccount(recipient.get());
       }//end synchronize

      }// end for

      //清空交易池 transactionPool.clearTransactions(); } }

TransactionPool.java

package com.ppblock.blockchain.core;

import com.google.common.base.Objects; import org.springframework.stereotype.Component;

import java.util.ArrayList; import java.util.List;

/**

  • 交易池

  • @author yangjian

  • @since 18-4-23 */ @Component public class TransactionPool {

    private List<Transaction> transactions = new ArrayList<>();

/**
 * 添加交易
 * @param transaction
 */
public void addTransaction(Transaction transaction) {

    boolean exists = false;
    //检验交易是否存在
    for (Transaction tx : this.transactions) {
        if (Objects.equal(tx.getTxHash(), transaction.getTxHash())) {
            exists = true;
        }
    }
    if (!exists) {
        this.transactions.add(transaction);
    }
}

public List<Transaction> getTransactions() {
    return transactions;
}

/**
 * 清空交易池
 */
public void clearTransactions() {
    this.transactions.clear();
}


文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链兄弟赞同其观点或证实其描述。

attachments-2018-02-kL1zBfXx5a7ffd0b78798.jpg

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
不写代码的码农
社区运营-小以

558 篇文章

作家榜 »

  1. 社区运营-小以 558 文章
  2. 社区运营-小链 244 文章
  3. 于中阳Mercina-zy 79 文章
  4. 涂晶 75 文章
  5. 李晓琼 44 文章
  6. 兄弟连区块链培训 42 文章
  7. 吴寿鹤 36 文章
  8. John-smith 25 文章