changeset 110:eab161e557bd

fix Refactor
author akahori
date Mon, 19 Nov 2018 12:31:36 +0900
parents 2e64b927388c
children 671246274719
files src/main/java/christie/blockchain/Block.java src/main/java/christie/blockchain/BlockChain.java src/main/java/christie/blockchain/BlockHeader.java src/main/java/christie/blockchain/ECKey.java src/main/java/christie/blockchain/HashUtil.java src/main/java/christie/blockchain/Miner.java src/main/java/christie/blockchain/Transaction.java
diffstat 7 files changed, 281 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/christie/blockchain/Block.java	Mon Nov 05 10:16:28 2018 +0900
+++ b/src/main/java/christie/blockchain/Block.java	Mon Nov 19 12:31:36 2018 +0900
@@ -1,17 +1,28 @@
 package christie.blockchain;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 public class Block {
     private BlockHeader header;
 
     private String data;
 
+    private List<Transaction> transactionsList = new CopyOnWriteArrayList<>();
+
     public Block(long timestamp, String data){
-        this("".getBytes(), timestamp, data);
+        this("".getBytes(), timestamp, data, null);
+    }
+    public Block(byte[] parentHash, long timestamp, String data){
+        this(parentHash, timestamp, data, null);
     }
 
-    public Block(byte[] parentHash, long timestamp, String data) {
+    public Block(byte[] parentHash, long timestamp, String data, List<Transaction> transactionsList) {
         this.header = new BlockHeader(parentHash, timestamp);
         this.data = data;
+        if (this.transactionsList == null) {
+            this.transactionsList = new CopyOnWriteArrayList<>();
+        }
     }
 
     public BlockHeader getHeader(){
@@ -34,17 +45,14 @@
         return data;
     }
 
-    public byte[] calcHash(){
-        return this.header.calcHash();
-    }
-
-    public void mineBlock(int difficulty){
-        this.header.mineBlock(difficulty);
-    }
+    public void setNonce(long nonce) { this.header.setNonce(nonce);}
 
     public long getNonce(){
         return this.header.getNonce();
     }
 
+    public byte[] getPresentHashWithoutNonce(){
+        return this.header.getPresentHashWithoutNonce();
+    }
 
 }
--- a/src/main/java/christie/blockchain/BlockChain.java	Mon Nov 05 10:16:28 2018 +0900
+++ b/src/main/java/christie/blockchain/BlockChain.java	Mon Nov 19 12:31:36 2018 +0900
@@ -3,6 +3,7 @@
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 public class BlockChain {
 
@@ -11,19 +12,19 @@
     public static void main(String[] args) {
         int difficulty = 1;
         BlockChain blockChain = new BlockChain();
-
+        Miner miner = new Miner();
         long startTime = System.currentTimeMillis();
 
         Block genesisBlock = blockChain.createGenesisBlock("Hi im the first block");
-        genesisBlock.mineBlock(difficulty);
+        miner.mineBlock(genesisBlock, difficulty);
         System.out.println("Hash for block 1 : " + genesisBlock.getData() + " Nonce : " + genesisBlock.getNonce());
 
         Block secondBlock = blockChain.createNewBlock(genesisBlock, "Yo im the second block");
-        secondBlock.mineBlock(difficulty);
+        miner.mineBlock(secondBlock, difficulty);
         System.out.println("Hash for block 2 : " + secondBlock.getData() + " Nonce : " + secondBlock.getNonce());
 
         Block thirdBlock = blockChain.createNewBlock(secondBlock, "Hey im the third block");
-        thirdBlock.mineBlock(difficulty);
+        miner.mineBlock(thirdBlock, difficulty);
         System.out.println("Hash for block 3 : " + thirdBlock.getData() + " Nonce : " + thirdBlock.getNonce());
 
 
@@ -50,18 +51,12 @@
             currentBlock = blockList.get(i);
             parentBlock = blockList.get(i-1);
 
-
-            if(!Arrays.equals(currentBlock.getPresentHash(), currentBlock.calcHash())){
-                System.out.println("Current Hashes not equal");
-                return false;
-            }
-
             if(!Arrays.equals(parentBlock.getPresentHash(), currentBlock.getParentHash())){
                 System.out.println("Previous Hashes not equal");
                 return false;
             }
 
-            String hashStr = new String(currentBlock.getPresentHash(), Charset.forName("utf-16"));
+            String hashStr = new String(currentBlock.getPresentHash(), Charset.forName("utf-8"));
             if(!hashStr.substring( 0, difficulty).equals(hashTarget)) {
                 System.out.println("This block hasn't been mined");
                 return false;
--- a/src/main/java/christie/blockchain/BlockHeader.java	Mon Nov 05 10:16:28 2018 +0900
+++ b/src/main/java/christie/blockchain/BlockHeader.java	Mon Nov 19 12:31:36 2018 +0900
@@ -1,5 +1,7 @@
 package christie.blockchain;
 
+import org.bouncycastle.util.BigIntegers;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
@@ -15,30 +17,36 @@
 
     private long nonce;
 
+    HashUtil hashUtil = new HashUtil();
+
     public BlockHeader(byte[] parentHash, long timestamp) {
         this.parentHash = parentHash;
         this.timestamp = timestamp;
-        this.presentHash = calcHash();
     }
 
-    public byte[] calcHash(){
-        HashUtil hashUtil = new HashUtil();
+    public byte[] getHash(boolean withNonce){
+
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
 
         byte[] timestampByte = BigInteger.valueOf(this.timestamp).toByteArray();
 
-        byte[] nonceByte = BigInteger.valueOf(this.nonce).toByteArray();
-
-        ByteArrayOutputStream output = new ByteArrayOutputStream();
-
         try {
             output.write(parentHash);
             output.write(timestampByte);
-            output.write(nonceByte);
         } catch (IOException e) {
             e.printStackTrace();
         }
 
-        return hashUtil.sha256(output.toByteArray());
+        if(withNonce){
+            byte[] nonceByte = BigInteger.valueOf(this.nonce).toByteArray();
+            try {
+                output.write(nonceByte);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return output.toByteArray();
 
     }
 
@@ -47,12 +55,12 @@
     }
 
     public byte[] getPresentHash() {
-        if(this.presentHash == null){
-            this.presentHash = calcHash();
-        }
-        return this.presentHash;
+        return hashUtil.sha256(getHash(true));
     }
 
+    public byte[] getPresentHashWithoutNonce(){
+        return getHash(false);
+    }
 
     public long getTimestamp() {
         return timestamp;
@@ -62,17 +70,7 @@
         this.timestamp = timestamp;
     }
 
-    public void mineBlock(int difficulty) {
-        String target = new String(new char[difficulty]).replace('\0', '0');
-        String hashStr = new String(presentHash, Charset.forName("utf-16"));
-
-        while(!hashStr.substring( 0, difficulty).equals(target)) {
-            this.nonce ++;
-            this.presentHash = calcHash();
-            hashStr = new String(this.presentHash, Charset.forName("utf-16"));
-        }
-        System.out.println("Block Mined!!! : " + hashStr);
-    }
+    public void setNonce(long nonce) { this.nonce = nonce; }
 
     public long getNonce(){
         return this.nonce;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/christie/blockchain/ECKey.java	Mon Nov 19 12:31:36 2018 +0900
@@ -0,0 +1,102 @@
+package christie.blockchain;
+
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+
+
+public class ECKey {
+
+    public static final ECDomainParameters CURVE;
+    public static final ECParameterSpec CURVE_SPEC;
+
+    public static final BigInteger HALF_CURVE_ORDER;
+    private static final SecureRandom secureRandom;
+
+    private final PrivateKey privateKey;
+    private final PublicKey publicKey;
+    private final Provider provider;
+
+    static {
+        X9ECParameters params = SECNamedCurves.getByName("secp256k1");
+        CURVE = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH());
+        CURVE_SPEC = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH());
+        HALF_CURVE_ORDER = params.getN().shiftRight(1);
+        secureRandom = new SecureRandom();
+    }
+
+    public ECKey() {
+        this(secureRandom);
+    }
+
+    public ECKey(SecureRandom secureRandom) {
+        this(new BouncyCastleProvider(), secureRandom);
+    }
+
+
+    public ECKey(Provider provider, SecureRandom secureRandom) {
+        this.provider = provider;
+
+        KeyPairGenerator keyGen;
+        try {
+            keyGen = KeyPairGenerator.getInstance("EC");
+            ECGenParameterSpec SECP256K1_CURVE = new ECGenParameterSpec("secp256k1");
+            keyGen.initialize(SECP256K1_CURVE);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new AssertionError(ex);
+        } catch (InvalidAlgorithmParameterException ex) {
+            throw new AssertionError(ex);
+        }
+
+        KeyPair keyPair = keyGen.generateKeyPair();
+
+        this.privateKey = keyPair.getPrivate();
+        this.publicKey = keyPair.getPublic();
+
+    }
+
+    private static ECPoint extractPublicKey(final ECPublicKey ecPublicKey) {
+        final java.security.spec.ECPoint publicPointW = ecPublicKey.getW();
+        final BigInteger xCoord = publicPointW.getAffineX();
+        final BigInteger yCoord = publicPointW.getAffineY();
+
+        return CURVE.getCurve().createPoint(xCoord, yCoord);
+    }
+
+    public byte[] applyECDSASig(byte[] input) {
+        Signature dsa;
+        byte[] output;
+
+        if (privateKey == null)
+            throw new RuntimeException();
+        try {
+            dsa = Signature.getInstance("ECDSA", "BC");
+            dsa.initSign(privateKey);
+            dsa.update(input);
+            output = dsa.sign();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return output;
+    }
+
+    public static boolean verifyECDSASig(byte[] data, byte[] signature, PublicKey publicKey) {
+        try {
+            Signature ecdsaVerify = Signature.getInstance("ECDSA", "BC");
+            ecdsaVerify.initVerify(publicKey);
+            ecdsaVerify.update(data);
+            return ecdsaVerify.verify(signature);
+        }catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
--- a/src/main/java/christie/blockchain/HashUtil.java	Mon Nov 05 10:16:28 2018 +0900
+++ b/src/main/java/christie/blockchain/HashUtil.java	Mon Nov 19 12:31:36 2018 +0900
@@ -42,4 +42,6 @@
         return resBuf;
     }
 
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/christie/blockchain/Miner.java	Mon Nov 19 12:31:36 2018 +0900
@@ -0,0 +1,70 @@
+package christie.blockchain;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+
+
+public class Miner {
+
+    HashUtil hashUtil = new HashUtil();
+
+
+    public void mineBlock(Block newBlock, int difficulty) {
+        long nonce = 0;
+
+
+        //byte[] target = new String(new char[difficulty]).replace('\0', '0').getBytes();
+        String target = new String(new char[difficulty]).replace('\0', '0');
+        byte[] hash = newBlock.getPresentHashWithoutNonce();
+
+        String hashStr = new String(hashUtil.sha256(hash), Charset.forName("utf-8"));
+
+
+        while(!hashStr.substring( 0, difficulty).equals(target)) {
+            nonce ++;
+            byte[] concat = Arrays.concatenate(hash, BigInteger.valueOf(nonce).toByteArray());
+            hashStr = new String(hashUtil.sha256(concat), Charset.forName("utf-8"));
+        }
+        newBlock.setNonce(nonce);
+        System.out.println("Block Mined!!! : " + hashStr);
+
+
+
+    }
+
+    public boolean increment(byte[] bytes) {
+        final int startIndex = 0;
+        int i;
+        for (i = bytes.length - 1; i >= startIndex; i--) {
+            bytes[i]++;
+            if (bytes[i] != 0)
+                break;
+        }
+
+        return (i >= startIndex || bytes[startIndex] != 0);
+    }
+
+    public int compareTo(byte[] buffer1, int offset1, int length1,
+                         byte[] buffer2, int offset2, int length2) {
+        // Short circuit equal case
+        if (buffer1 == buffer2 &&
+                offset1 == offset2 &&
+                length1 == length2) {
+            return 0;
+        }
+        int end1 = offset1 + length1;
+        int end2 = offset2 + length2;
+        for (int i = offset1, j = offset2; i < end1 && j < end2; i++, j++) {
+            int a = (buffer1[i] & 0xff);
+            int b = (buffer2[j] & 0xff);
+            if (a != b) {
+                return a - b;
+            }
+        }
+        return length1 - length2;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/christie/blockchain/Transaction.java	Mon Nov 19 12:31:36 2018 +0900
@@ -0,0 +1,62 @@
+package christie.blockchain;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+// インターフェイスにしたほうがいいかもしれない. 後からdataの内容変える可能性がある.
+public class Transaction {
+    private byte[] hash;
+
+    private long nonce;
+
+    private byte[] sendAddress;
+
+    private byte[] receiveAddress;
+
+    private byte[] data;
+
+    private long timestamp;
+
+    private byte[] signature;
+
+    //public ArrayList<TransactionInput> inputs = new ArrayList<TransactionInput>();
+    //public ArrayList<TransactionOutput> outputs = new ArrayList<TransactionOutput>();
+
+
+    public Transaction(byte[] sendAddress, byte[] receiveAddress, byte[] data){
+        this.sendAddress = sendAddress;
+        this.receiveAddress = receiveAddress;
+        this.data = data;
+
+    }
+/*
+    public Transaction(byte[] from, byte[] to, byte[] value,  ArrayList<TransactionInput> inputs) {
+        this.sendAddress = from;
+        this.receiveAddress = to;
+        this.value = value;
+        this.inputs = inputs;
+    }
+*/
+    public byte[] calcHash(){
+        HashUtil hashUtil = new HashUtil();
+
+        byte[] timestampByte = BigInteger.valueOf(this.timestamp).toByteArray();
+
+        byte[] nonceByte = BigInteger.valueOf(this.nonce).toByteArray();
+
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+        try {
+            output.write(hash);
+            output.write(timestampByte);
+            output.write(nonceByte);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return hashUtil.sha256(output.toByteArray());
+
+    }
+
+}