【区块链】——区块链学习初探(二)

Java实现比特币区块链工具包

结合上一篇的介绍:https://blog.csdn.net/NEU_LightBulb/article/details/103086867

以下就是代码介绍想看源码直接:

https://github.com/zjw271208550/learn/tree/master/blockchain-core

  • 工程结构

  • 实体类

Block

区块的数据结构的模板,也是上一篇文章中介绍的最原始的区块结构,其内部的方法会根据实际业务情况修改

BlockChain

上一篇文章中介绍的最原始的链结构,实际中链不可能长时间的存在于内存中,而是存在本地的,所以这个仅仅是一个模板,其内部的方法会根据实际业务情况修改

TransactionGroup

交易的实体类,也是上一篇文章中介绍的最原始的交易结构

TransactionIn

输入交易的实体类,也是上一篇文章中介绍的最原始的输入交易结构

TransactionOut

输出交易的实体类,也是上一篇文章中介绍的最原始的输出交易结构

TransactionOutUnspent

未输出交易的实体类,也是上一篇文章中介绍的最原始的未输出交易结构
  • 静态方法类

  • Crypt

加密、签名相关的方法,使用bouncycastle的椭圆曲线算法进行非对称加密,包含的方法如下

    /**    
     * Java 的非对称加密的密钥是配对生成的
     */
    public static Map<String, Key> generateECKeyPair() 
            throws NoSuchAlgorithmException,NoSuchProviderException {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE_EC,new SecureRandom());
        //生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //公钥
        ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
        //私钥
        ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
        //将密钥存储在map中
        Map<String, Key> keyMap = new HashMap<String, Key>();
        keyMap.put(Consts.KEY_PUBLIC_MAP, publicKey);
        keyMap.put(Consts.KEY_PRIVATE_MAP, privateKey);
        return keyMap;
    }

    /**
     * 找到一种 GayGay的方法实现由随机串生成私钥,实际上是生成密钥对但只返回私钥
     */
    public static byte[] generateECPrivateKeyFromRandom(byte[] random)
            throws NoSuchAlgorithmException,NoSuchProviderException{
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        keyPairGenerator.initialize(KEY_SIZE_EC,new SecureRandom(random));
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
        return privateKey.getEncoded();
    }

    /**
     * 从生成的密钥对中获得私钥
     */
    public static byte[] getECPrivateKey(Map<String, Key> keyMap) {
        ECPrivateKey key = (ECPrivateKey) keyMap.get(Consts.KEY_PRIVATE_MAP);
        return key.getEncoded();
    }

    /**
     * 从生成的密钥对中获得公钥
     */
    public static byte[] getECPublicKey(Map<String, Key> keyMap){
        ECPublicKey key = (ECPublicKey) keyMap.get(Consts.KEY_PUBLIC_MAP);
        return key.getEncoded();
    }


    /**
     * 使用签名者私钥对数据散列值签名
     */
    public static byte[] doSignature(byte[] data,byte[] privateKey)
            throws NoSuchAlgorithmException,NoSuchProviderException,
            InvalidKeySpecException,InvalidKeyException,SignatureException {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        PrivateKey pKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        Signature signature = Signature.getInstance(KEY_SIGNATURE_INS_EC);
        signature.initSign(pKey);
        signature.update(data);
        return signature.sign();
    }

    /**
     * 使用签名者公钥、数据散列值来验证签名
     */
    public static boolean verifySignature(byte[] data,byte[] publicKey,byte[] sign)
            throws NoSuchAlgorithmException,NoSuchProviderException,
                    InvalidKeySpecException,InvalidKeyException,SignatureException {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory  keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        PublicKey pKey = keyFactory.generatePublic(x509EncodedKeySpec);
        Signature  signature = Signature.getInstance(KEY_SIGNATURE_INS_EC);
        signature.initVerify(pKey);
        signature.update(data);
        return signature.verify(sign);
    }

    /**
     * 使用私钥对散列化数据加密
     */
    public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) 
            throws NoSuchAlgorithmException,NoSuchProviderException, NoSuchPaddingException,
                InvalidKeySpecException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        PrivateKey pKey = parsePrivateKey(privateKey);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_CIPHER_EC,KEY_PROVIDER_CIPHER_EC);
        cipher.init(Cipher.ENCRYPT_MODE, pKey);
        return cipher.doFinal(data);
    }

    /**
     * 使用公钥对加密数据解密
     */
    public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) 
            throws NoSuchAlgorithmException,NoSuchProviderException, NoSuchPaddingException,
                InvalidKeySpecException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        PublicKey pKey = parsePublicKey(publicKey);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM_CIPHER_EC,KEY_PROVIDER_CIPHER_EC);
        cipher.init(Cipher.ENCRYPT_MODE, pKey);
        return cipher.doFinal(data);
    }

    /**
     * Base64编码
     */
    public static String bytes2Base64String(byte[] key){
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * Base64解码
     */
    public static byte[] base64String2Bytes(String key) throws IOException {
        return (new BASE64Decoder()).decodeBuffer(key);
    }


    /**
     * 由公钥获得私钥
     */
    public static byte[] getECPublicKeyFromPrivateKey(byte[] privateKey)
            throws NoSuchAlgorithmException,NoSuchProviderException,InvalidKeySpecException{
        ECPrivateKey pKey = (ECPrivateKey)parsePrivateKey(privateKey);
        ECParameterSpec parameter = pKey.getParameters();
        ECPoint Q = parameter.getG().multiply(pKey.getD());
        byte[] publicDerBytes = Q.getEncoded(false);
        ECPoint point = parameter.getCurve().decodePoint(publicDerBytes);
        ECPublicKeySpec publicKeySpec =
                new ECPublicKeySpec(point,pKey.getParameters());

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        ECPublicKey publicKey = (ECPublicKey)keyFactory.generatePublic(publicKeySpec);
        return publicKey.getEncoded();
    }

private static PrivateKey parsePrivateKey(byte[] key)
            throws NoSuchAlgorithmException,NoSuchProviderException,InvalidKeySpecException{
        //取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        //生成私钥
        return keyFactory.generatePrivate(pkcs8KeySpec);
    }

    private static PublicKey parsePublicKey(byte[] key)
            throws NoSuchAlgorithmException,NoSuchProviderException,InvalidKeySpecException{
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM_EC,KEY_PROVIDER_EC);
        //生成私钥
        return keyFactory.generatePublic(x509KeySpec);
    }
  • HashFunction

Hash相关操作的方法:

    /**
     * 生成该区块的 Hash
     * @param block 区块
     * @return Hash
     */
    public static String generateHash(Block block){
        MessageDigest messageDigest;

        if(null==block.getData() && null==block.getPreviousHash())
            throw new RuntimeException("data or previous-hash is null");

        StringBuilder nocodeBuilder = new StringBuilder();
        nocodeBuilder.append(block.getIndex());
        nocodeBuilder.append(block.getCreateTimestamp());
        for(TransactionGroup tx:block.getData()) {
            nocodeBuilder.append(tx.toString());
        }
        nocodeBuilder.append(block.getPreviousHash());
        nocodeBuilder.append(block.getHashDifficulty());
        String nocode = nocodeBuilder.toString();

        int hashOffset = 0;
        String encode = "";

        try{
            messageDigest = MessageDigest.getInstance(Consts.ENCRYPT_INSTANCE);
            while (true) {
                String nocodetmp = nocode + hashOffset;
                messageDigest.update(nocodetmp.getBytes(Consts.ENCRYPT_BYTES_CODING));
                encode = bytes2Hex(messageDigest.digest());
                if(checkHashDifficulty(encode,block.getHashDifficulty())) {
                    block.setHashOffset(hashOffset);
                    break;
                }
                else {
                    hashOffset = hashOffset + 1;
                    encode = "";
                    nocodetmp = "";
                }
            }
        }catch (NoSuchAlgorithmException e){
            throw new RuntimeException("error on loading SHA-256");
        }catch (UnsupportedEncodingException e) {
            throw new RuntimeException("error on loading UTF-8");
        }
        return encode;
    }

    /**
     * 检查生成的 Hash是否符合 Difficulty的要求
     * @param hash Hash
     * @param difficulty 难度
     * @return 是否
     */
    private static boolean checkHashDifficulty(String hash,int difficulty){
        String hashBinary = hex2Binary(hash);
        return hashBinary.startsWith(generatePrefix(difficulty));
    }

    /**
     * bytes转16进制数的字符串
     * @param bytes bytes
     * @return 16进制数的字符串
     */
    private static String bytes2Hex(byte[] bytes){
        StringBuilder stringBuilder = new StringBuilder("");
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        for (byte b : bytes) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * bytes转2进制数的字符串
     * @param bytes bytes
     * @return 2进制数的字符串
     */
    private static String bytes2Binary(byte[] bytes){
        StringBuilder stringBuilder = new StringBuilder("");
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        for (byte b : bytes) {
            stringBuilder.append(Long.toString(b & 0xff, 2));
        }
        return stringBuilder.toString().substring(0, stringBuilder.length() - 1);
    }

    /**
     * 16进制数的字符串转2进制数的字符串
     * @param hex 16进制数的字符串
     * @return 2进制数的字符串
     */
    private static String hex2Binary(String hex){
        char[] strChar=hex.toCharArray();
        StringBuilder stringBuilder = new StringBuilder("");
        for(char c:strChar){
            int ihex = Integer.valueOf(String.valueOf(c),16);
            String sbin = Integer.toBinaryString(ihex);
            String sbinf = String.format("%04d",Integer.valueOf(sbin));
            stringBuilder.append(sbinf);
        }
        return stringBuilder.toString();
    }
    
    /**
     * 生成难度对应的 Hash前缀用于难度验证
     * @param offset 难度
     * @return 前缀字符串
     */
    private static String generatePrefix(int offset){
        StringBuilder prefix = new StringBuilder();
        for (int i=0;i<offset;i++){
            prefix.append('0');
        }
        return prefix.toString();
    }

    /**
     * SHA256编码
     * @param nocode 未编码字符串
     * @return 编码后字符串
     */
    public static String getSHA256Code(String nocode){
        String encode;
        try{
            MessageDigest messageDigest = MessageDigest.getInstance(Consts.ENCRYPT_INSTANCE);
            messageDigest.update(nocode.getBytes(Consts.ENCRYPT_BYTES_CODING));
            encode = bytes2Hex(messageDigest.digest());
        }catch (NoSuchAlgorithmException e){
            throw new RuntimeException("error on loading SHA-256");
        }catch (UnsupportedEncodingException e) {
            throw new RuntimeException("error on loading UTF-8");
        }
        return encode;
    }
  • Transaction

交易的相关方法

    /**
     * 生成交易组的 ID
     */
    public static String generateId(TransactionGroup transaction){
        StringBuilder inId = new StringBuilder(transaction.getFromAddress());
        for(TransactionIn txIn:transaction.getTxIns()){
            inId.append(txIn.getOutFromTxId()+txIn.getOutFromIndex());
        }
        StringBuilder outId = new StringBuilder("");
        for(TransactionOut txOut:transaction.getTxOuts()){
            inId.append(txOut.getToAddress()+txOut.getInfo().getDataEncryptString());
        }
        return HashFunction.getSHA256Code(inId.toString()+outId.toString());
    }


    /**
     * 给一个 TxInORM 签名
     */
    public static String signForTransactionIn(String bodyId,
                                              TransactionIn txIn,
                                              String privateKey,
                                              List<TransactionOutUnspent> unspents)
            throws IOException, NoSuchAlgorithmException, NoSuchProviderException,
                    InvalidKeySpecException, InvalidKeyException, SignatureException {
       String idToSign = bodyId;

       TransactionOutUnspent referencedUnspentTxOut =
               findUnspentTxOut(txIn.getOutFromTxId(), txIn.getOutFromIndex(), unspents);
       if(null == referencedUnspentTxOut)
           throw new RuntimeException("没有匹配的未使用TxOut");
       String referencedAddress = referencedUnspentTxOut.getToAddress();

       if(!getPublicKey(privateKey).equals(referencedAddress))
           throw new RuntimeException("私钥生成的公钥与地址不符");

       String signature = bytes2Base64String(
               doSignature(
                       base64String2Bytes(idToSign),
                       base64String2Bytes(privateKey)
               )
       );

       return signature;
    }

    /**
     * 给一个 创始TxInORM 签名
     */
    public static String signForTransactionIn0(String bodyId,
                                                String addressTo,
                                                String privateKey)
            throws IOException, NoSuchAlgorithmException, NoSuchProviderException,
            InvalidKeySpecException, InvalidKeyException, SignatureException {
        String idToSign = bodyId;

        if(!getPublicKey(privateKey).equals(addressTo))
            throw new RuntimeException("私钥生成的公钥与地址不符");

        String signature = bytes2Base64String(
                doSignature(
                        base64String2Bytes(idToSign),
                        base64String2Bytes(privateKey)
                )
        );

        return signature;
    }

    /**
     * 根据私钥 Base64编码字符串获得 Base64编码后的公钥字符串
     */
    public static String getPublicKey(String privateKey)
            throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
        byte[] privateK = base64String2Bytes(privateKey);
        byte[] publicK = getECPublicKeyFromPrivateKey(privateK);
        return bytes2Base64String(publicK);
    }


    /**
     * 判断是否是合法的交易组
     */
    public static boolean isLegalTransaction(TransactionGroup transaction,
                                             List<TransactionOutUnspent> unspents)
            throws IOException,NoSuchAlgorithmException,NoSuchProviderException,
                InvalidKeySpecException,InvalidKeyException,SignatureException{
        //判断 Id是否合法
        if(!generateId(transaction).equals(transaction.getId()) ){
            log.error("交易序列不合法:交易序列 ID不合法");
            return false;
        }


        //遍历所有的 txIn判断是否合法
        List<BlockData> txInInfos = new ArrayList<>();
        for(TransactionIn in:transaction.getTxIns()){
            //some of the txIns are invalid in t
            if(!isLegalTransactionIn(in,transaction,unspents)){
                log.error("交易序列不合法:发现签名不合法的 TxInORM,idx为{}",in.getOutFromIndex());
                return false;
            }
            txInInfos.add(getTransactionInInfo(in,unspents));
        }

        List<BlockData> txOutInfos = new ArrayList<>();
        for(TransactionOut out :transaction.getTxOuts()){
            txOutInfos.add(out.getInfo());
        }

        if(txInInfos.size()!=txOutInfos.size()) {
            log.error("交易输入 TxIn与交易输出 TxOut数量不符");
            return false;
        }

        for(BlockData txInInfo:txInInfos){
            int tmp=0;
            for(BlockData txOutInfo:txOutInfos) {
                if (txInInfo.equals(txOutInfo)){
                    break;
                }else {
                    tmp+=1;
                }
            }
            if(tmp==txOutInfos.size()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判断是否是合法的 txIn
     */
    private static boolean isLegalTransactionIn(TransactionIn txIn,
                                                TransactionGroup transaction,
                                                List<TransactionOutUnspent> unspents)
            throws IOException,NoSuchAlgorithmException,NoSuchProviderException,
                    InvalidKeySpecException,InvalidKeyException,SignatureException{
        //找到 txIn 引用的 txOutUnspent
        TransactionOutUnspent referencedUTxOut =
                findUnspentTxOut(txIn.getOutFromTxId(),txIn.getOutFromIndex(),unspents);

        //如果找不到说明 txIn 不合法
        if(null == referencedUTxOut) {
            log.error("交易输入 TxIn不合法:找不到引用的未使用交易输出 TxOutUnspent");
            return false;
        }

        String senderAddress = referencedUTxOut.getToAddress();

        //判断签名合法性
        return verifySignature(
                base64String2Bytes(transaction.getId()),
                base64String2Bytes(senderAddress),
                base64String2Bytes(txIn.getSignature()));
    }

    /**
     * 找到与交易输入匹配的未使用的交易输出
     */
    private static BlockData getTransactionInInfo(TransactionIn txIn,
                                                List<TransactionOutUnspent> unspents){
        TransactionOutUnspent referencedUTxOut =
                findUnspentTxOut(txIn.getOutFromTxId(),txIn.getOutFromIndex(),unspents);
        return referencedUTxOut.getInfo();
    }

    /**
     * 找到与 txOut 匹配的 txOutUnspent
     */
    private static TransactionOutUnspent findUnspentTxOut(String txInId,
                                                          int txInIndex,
                                                          List<TransactionOutUnspent> unspents){
        for(TransactionOutUnspent unspent: unspents){
            if(unspent.getOutFromTxId().equals(txInId) &&
                    unspent.getOutFromIndex() == txInIndex)
                return unspent;
        }
        return null;
    }
  • 使用关系型数据库作为元数据载体的工具

  • 元数据结构

public abstract class BlockData {
    private String dataId;
    private String sha256_data;

    public BlockData(String dataId, String dataString) {
        this.dataId = dataId;
        this.sha256_data = HashFunction.getSHA256Code(dataString);
    }

    public BlockData(String dataId, String dataString,boolean hasCoding) {
        this.dataId = dataId;
        if(hasCoding)
            this.sha256_data = dataString;
        else
            this.sha256_data = HashFunction.getSHA256Code(dataString);
    }

    public String getDataId() {
        return dataId;
    }

    public void setDataId(String dataId) {
        this.dataId = dataId;
    }

    public String getSHA256Data() {
        return sha256_data;
    }

    public void setData(String dataString) {
        this.sha256_data = HashFunction.getSHA256Code(dataString);
    }

    public void setSHA256Data(String sha256_data) {
        this.sha256_data = sha256_data;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof  BlockData){
            return this.dataId.equals(((BlockData) obj).getDataId())&&
                    this.sha256_data.equals(((BlockData) obj).getSHA256Data());
        }else return false;
    }

    public String getDataEncryptString(){
        return this.sha256_data;
    }
}
  • ORM

BlockORM

int:index
long:createTimestamp
long:createTimeUse
LinkedList<TxORM>:data
String:hash
String:previousHash
int:hashOffset
int:hashDifficulty

与数据库交互的区块实体

只有构造方法和Getter、Setter

TxInORM

String:txId
String:preTxId
int:preTxIdx
String:sign

与数据库交互的输入交易实体

只有构造方法和Getter、Setter

TxOutORM

String:txId
String:addressTo
String:dataId
String:data

与数据库交互的输出交易实体

只有构造方法和Getter、Setter

TxORM

int:blockIdx
String:id
String:fromAddress
List<TxInORM>:txInORMS
List<TxOutORM>:txOutORMS

与数据库交互的交易实体

只有构造方法和Getter、Setter

UTxOutORM

String:publicKey
String:dataId
String:data
String:txId
int:txIdx

与数据库交互的未输出交易实体

只有构造方法和Getter、Setter

  • Mybatis Mapper

这里要首先说一下RDB中区块、输入交易、输出交易、交易、未输出交易的表结构从上文的ORM结构就能看出来,这些都是预先建好的表:

根据区块位置获得区块信息

SELECT n_index,dt_create,n_use_time,c_hash,c_prehash,n_offset,n_difficaulty FROM db_data.t_blockchain WHERE n_index=#{index}

根据区块位置获得区块内交易列表SELECT n_block_index,c_id,c_from_addr FROM db_data.t_txs WHERE n_block_index=#{n_index}
获取未上链的交易SELECT n_block_index,c_id,c_from_addr FROM db_data.t_txs WHERE n_block_index ISNULL
根据交易ID获取该交易的输入交易列表SELECT c_tx_id,c_pretx_id,n_pretx_idx,c_sign FROM db_data.t_txins WHERE c_tx_id=#{c_id}
根据交易ID获取该交易的输出交易列表SELECT c_tx_id,c_address_to,c_data_id,c_data FROM db_data.t_txouts WHERE c_tx_id=#{c_id}
插入一个区块INSERT INTO db_data.t_blockchain (n_index,dt_create,n_use_time,c_hash,c_prehash,n_offset,n_difficaulty) VALUES(#{index},#{createTimestamp},#{createTimeUse},#{hash},#{previousHash},#{hashOffset},#{hashDifficulty})
更新刚刚上链的交易的区块位置

UPDATE db_data.t_txs SET n_block_index=#{bid} WHERE c_id=#{cid}

新增一个输入交易INSERT INTO db_data.t_txins (c_tx_id,c_pretx_id,n_pretx_idx,c_sign) VALUES(#{txId},#{preTxId},#{preTxIdx},#{sign})
新增一个输出交易INSERT INTO db_data.t_txouts (c_tx_id,c_address_to,c_data_id,c_data) VALUES(#{txId},#{addressTo},#{dataId},#{data})
根据数据所有者(公钥)获取未输出交易列表SELECT c_publickey,c_data_id,c_data,c_txid,n_txidx FROM db_data.t_utxos WHERE c_publickey=#{publicKey}
根据交易ID获取未输出交易列表SELECT c_publickey,c_data_id,c_data,c_txid,n_txidx FROM db_data.t_utxos WHERE c_txid=#{txId}
根据交易ID和输出交易位置获取未输出交易SELECT c_publickey,c_data_id,c_data,c_txid,n_txidx FROM db_data.t_utxos WHERE c_txid=#{txId} AND n_txidx=#{txIds}
根据数据ID取未输出交易SELECT c_publickey,c_data_id,c_data,c_txid,n_txidx FROM db_data.t_utxos WHERE c_data_id=#{dataId}
插入一个未输出交易INSERT INTO db_data.t_utxos (c_publickey,c_data_id,c_data,c_txid,n_txidx) VALUES(#{publicKey},#{dataId},#{data},#{txId},#{txIdx})
根据数据ID删除一个未输出交易DELETE FROM db_data.t_utxos WHERE c_data_id=#{dataId}
获取链尾区块信息SELECT n_index,dt_create,n_use_time,c_hash,c_prehash,n_offset,n_difficaulty FROM db_data.t_blockchain ORDER BY n_index DESC LIMIT 1
获取创世块信息SELECT n_index,dt_create,n_use_time,c_hash,c_prehash,n_offset,n_difficaulty FROM db_data.t_blockchain WHERE n_index=1
  • 给Service调用的静态方法

    /**
     * 检查数据是否被篡改
     * @param mapper 继承 BCMapper 的 Mapper
     * @param dataInDB 要被检验的数据
     * @return 是否
     */
    public static boolean checkDataById(BCMapper mapper, BlockData dataInDB){
        UTxOutORM uTxOut = mapper.getUTxOutByDataId(dataInDB.getDataId());
        if(null == uTxOut){
            logger.error("该数据未在账本或未被挖掘");
            return false;
        }else {
            return uTxOut.getData().equals(dataInDB.getSHA256Data());
        }
    }

    /**
     * 检查是否已经创世
     * @param mapper 继承 BCMapper 的 Mapper
     * @return 是否
     */
    public static boolean hasInit(BCMapper mapper){
        BlockORM initBlockInfo = mapper.getInitBlockInfo();
        if(null==initBlockInfo){
            return false;
        }

        Block initBlock = ORM2EntityFunction.BlockOrm2Entity(initBlockInfo);
        String initHash = HashFunction.generateHash(initBlock);
        if(initHash.equals(initBlockInfo.getHash())){
            return true;
        }else {
            System.out.println("创世块HASH不合法");
            return false;
        }
    }

    /**
     * 创世
     * @param mapper 继承 BCMapper 的 Mapper
     * @return 成功与否
     */
    public static boolean initBlock(BCMapper mapper){
        Block initBlock = new Block(1,0,0,null,
                "","",0, Consts.HASH_DIFFICULTY_INIT);
        long start = new Date().getTime();
        String hash = HashFunction.generateHash(initBlock);
        long end = new Date().getTime();
        BlockORM initBlockORM = new BlockORM(1,0,end-start,hash,
                "",initBlock.getHashOffset(),Consts.HASH_DIFFICULTY_INIT);
        mapper.addOneBlock(initBlockORM);
        return true;
    }

    /**
     * 添加一个新的数据,数据准备上链
     * @param mapper 继承 BCMapper 的 Mapper
     * @param publicKey 数据所有者公钥
     * @param privateKey 数据所有者私钥
     * @param data 数据
     * @return 成功与否
     */
    public static boolean addNewData(BCMapper mapper,String publicKey,String privateKey, BlockData data)
    throws Exception{
        TransactionIn txIn = new TransactionIn("",1,null);
        TransactionOut txOut = new TransactionOut(publicKey,data);
        TransactionGroup tx = new TransactionGroup(
                publicKey,
                Arrays.asList(new TransactionIn[] {txIn}),
                Arrays.asList(new TransactionOut[] {txOut})
        );
        String sign = Transaction.signForTransactionIn0(tx.getId(), publicKey, privateKey);
        txIn.setSignature(sign);
        mapper.addOneTx(
                new TxORM(null,publicKey,tx.getId()));
        mapper.addOneTxIn(
                new TxInORM(tx.getId(), txIn.getOutFromTxId(), txIn.getOutFromIndex(), txIn.getSignature()));
        mapper.addOneTxOut(
                new TxOutORM(tx.getId(),txOut.getToAddress(),txOut.getInfo().getDataId(),txOut.getInfo().getSHA256Data()));
        return true;
    }

    /**
     * 挖掘未上链的数据,数据上链
     * @param mapper 继承 BCMapper 的 Mapper
     * @param publicKey 挖掘者公钥
     * @return 成功与否
     */
    public static boolean mineTransactions(BCMapper mapper,String publicKey) throws Exception{
        List<TxORM> txOrms = mapper.getTxsByNull();
        if(null == txOrms || txOrms.size()==0){
            return true;
        }
        /*
         * 此处会广播 txOrms给全部节点,一起算
         */

        BlockORM lastBlockInfo = mapper.getLastBlockInfo();
        LinkedList<TransactionGroup> txs = new LinkedList<>();

        for(TxORM txORM: txOrms){
            TransactionGroup tx = ORM2EntityFunction.TxOrm2Entity(txORM);

            //正确的TxId
            if(tx.getId().equals(txORM.getId())){
                for(TransactionIn txIn:tx.getTxIns()){
                    boolean check = Crypt.verifySignature(
                            Crypt.base64String2Bytes(tx.getId()),
                            Crypt.base64String2Bytes(txORM.getFromAddress()),
                            Crypt.base64String2Bytes(txIn.getSignature())
                    );
                    if(!check){
                        throw new RuntimeException("交易ID"+tx.getId()+",签名不合法");
                    }
                }
                txs.add(tx);
            }else {
                throw new RuntimeException("交易ID:"+txORM.getId()+",不合法");
            }
        }

        Block newBlock = new Block(
                lastBlockInfo.getIndex()+1,
                txs,
                lastBlockInfo.getHash(),
                lastBlockInfo.getHashDifficulty());

        BlockORM newBlockOrm = new BlockORM(
                newBlock.getIndex(),
                newBlock.getCreateTimestamp(),
                newBlock.getCreateTimeUse(),
                null,
                newBlock.getHash(),
                newBlock.getPreviousHash(),
                newBlock.getHashOffset(),
                newBlock.getHashDifficulty());
        mapper.addOneBlock(newBlockOrm);

        for(TxORM txORM: txOrms){
            List<TxOutORM> txOutOrms = txORM.getTxOutORMS();
            mapper.updateTxBlockId(newBlockOrm.getIndex(),txORM.getId());
            int idx=1;
            for(TxOutORM txOutORM:txOutOrms){
                mapper.addOneUTxOut(
                        new UTxOutORM(publicKey,txOutORM.getDataId(),txOutORM.getData(),txORM.getId(),idx));
                idx += 1;
            }
        }

        return true;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值