In the previous chapter, we mainly described the block chain, block, mining and so on, set the data format of the block, realize how to encrypt the block into the block chain to ensure the effectiveness of the block chain, and we also through the design of a data problem, It is necessary to have a certain computational power (PoW) to prove that a block is a new block in the block chain.
In this chapter, we will implement the following features
1. Create a simple wallet (wallet)
2, use our block chain to send the transaction (transaction)
This will result in our own encrypted currency.
Before we begin to understand the concept of this part in Bitcoin, trading is the core of bitcoin, and the only purpose of the block chain is to store transactions in a secure and reliable manner, and no one can modify them once they are created.
As long as you've developed a Web application, you know, in order to make a deal, you have to create it in the database: The Account table and the transaction sheet, the Account table contains information about each account, including the account's profile and the balance, and the transaction list holds each transaction from one account to another. But in Bitcoin, transactions are implemented in a way that is completely different from how they are implemented in Web applications. In the bit currency:
1, no account
2, no balance
3, no address
4, no money information
5. No payer, no payee.
Because the block chain is a completely open, open source database, we do not want to store any information about the user's privacy, so there is no money in the account table, there is no amount of money stored in the statement from one account to another account information, not to store the balance of the account information. Only the information of this transaction, then what is in the transaction. Let's go ahead and watch.
From the previous chapter, create your first block chain-part1 with Java, we already have a basic block chain, but in the block we are storing some useless information (data), we will replace this information with the transaction today, so that our block can also save a lot of transaction information, So that we can create our own encrypted currency. Note that this course was implemented on the basis of the previous course and relied on bouncycastle and Gson.
First step, prepare a wallet (wallet)
In the encrypted currency, the ownership of money can be transferred, in the block chain we call the transaction, each participant has a private address to send or collect money, which is similar to each of us in the bank has a unique account, where the address is similar to our account.
In our tutorial, wallets are used to store address information, and wallets can also create new deals for block chains.
Let's create a wallet and have our own public and private keys.
Import java.security.*;
public class Wallet {public Privatekey privatekey; public PublicKey PublicKey;}
At this point you may have questions about what the public and private key do. In fact, the public key function is the address, you can share your public key in order to get paid, and your private key is used to sign the transaction so that no one else can spend the amount unless it has your private key, so for everyone we have to protect our private key, Cannot disclose our private key information to other people. We also send our public key at the same time as we make the transaction to verify that our signature is valid and that no data has been tampered with.
The private key is used to sign data that is not intended to be tampered with, and the public key is used to verify the signature.
We create our public and private keys through a key pair (KeyPair), and the key pair uses an Elliptic curve encryption algorithm (ECDSA), which we create in the constructor in the Wallet class.
Import java.security.*;
public class Wallet {public Privatekey privatekey, public publickey publickey, public Wallet () {Generatekeypair ();} Publ IC void Generatekeypair () {try {keypairgenerator keyGen = keypairgenerator.getinstance ("ECDSA", "BC"); SecureRandom random = securerandom.getinstance ("sha1prng"); Ecgenparameterspec Ecspec = new Ecgenparameterspec ("Prime192v1"); Keygen.initialize (Ecspec, Random); KeyPair KeyPair = Keygen.generatekeypair (); Privatekey = Keypair.getprivate (); PublicKey = Keypair.getpublic (); }catch (Exception e) {throw new RuntimeException (e);}} }
You don't have to fully understand what the core logic of the Elliptic Curve encryption algorithm is, you just need it to create a public and private key, and the role of the public and private key separately.
Now that we have the approximate frame of the wallet (wallet) class, let's look at the transaction (transaction) class.
Step two, transactions, and digital signatures
Carry the following information in every transaction.
1, the money payer's public key information
2. Public key information of money payee
3, the amount of funds transferred
4, input, reference before the transaction, proof that the payer has funds can be sent
5, output, showing the relevant address accepted in this transaction (these outputs are referred to as input in the new transaction)
6, an encrypted signature, to prove that the owner's address can be sent transactions and the data has not been modified (to prevent third-party organizations to change the number of sent)
Let's create a trading class.
Import java.security.*; Import java.util.ArrayList;
The public class Transaction {TransactionID;//Transaction's hash number is PublicKey sender; reciepient; The recipient address public value;//the transfer amount to byte[] signature; Digitally sign to prevent others from sending money from our wallets,//Input list public arraylist<transactioninput> inputs = new Arraylist<transactioninput > ();
Output list
Public arraylist<transactionoutput> outputs = new arraylist<transactionoutput> (); How many transactions have been created private static int sequence = 0; Constructor public Transaction (PublicKey from, PublicKey to, float value, arraylist<transactioninput> inputs) {This.send ER = from; This.reciepient = to; This.value = value; This.inputs = inputs; }//Calculate hash value of transaction (for transaction number) private String Calulatehash () {sequence++;//Add sequence to prevent two different transactions have the same hash value return stringutil.applysha256 (Stringutil.getstringfromkey (sender) + stringutil.getstringfromkey (reciepient) + Float.tostring (value) + sequence); Let's create an empty transactioninput and Transactionoutput class, don't worry I'll fill in later and explain its purpose.
There are already ways to create and validate signatures and validate transactions in our trading classes, so what are the intentions of the signature and how do they work? The signature performs two very important tasks in our block chain: First, the signature is used to ensure that only the owner of the currency is allowed to send its own currency, and second, the signature is used to prevent others from attempting to tamper with the submitted transaction. That is, the private key is used to sign data, and the public key is used to verify its integrity.
For example: Xiaoming wants to send 2 encrypted currencies to Xiao Hong, they created the deal with their wallets and submitted them to a whole network of block chains as a new block, and a digger tried to tamper with the recipient's 2 encrypted currency to the little blue, but luckily, Xiaoming has signed the private key in the transaction data. This allows any node in the entire network to verify that the data has been tampered with by using Xiaoming's public key (since no other person's public key can be used to authenticate transactions).
We can see from the block class that our signature is a string of character data, so let's also create a method to generate the signature in the Stringutil class.
//Apply ECDSA signature and produce character array public static byte[] Applyecdsasig (privatekey privatekey, String input) {Signature DSA; byte[] Out put = new Byte[0]; try {DSA = signature.getinstance ("ECDSA", "BC"); Dsa.initsign (Privatekey); byte[] Strbyte = Input.getbytes (); dsa.update (Strbyte); byte[] Realsig = Dsa.sign (); output = Realsig; catch (Exception e) {throw new RuntimeException (e);} return output; ///Apply ECDSA Verify digital signature public static Boolean Verifyecdsasig (PublicKey publickey, String data, byte[] signature) {try {Signatu Re ecdsaverify = signature.getinstance ("ECDSA", "BC"); Ecdsaverify.initverify (PublicKey); Ecdsaverify.update (Data.getbytes ()); return ecdsaverify.verify (signature); }catch (Exception e) {throw new RuntimeException (e);}}
public static String Getstringfromkey (key key) {return Base64.getencoder (). Encodetostring (key.getencoded ());
Don't worry, most of them don't understand the content of these methods, all you need to know is that the Applyecdsasig method's input parameter is the payer's private key and the data information that needs to be encrypted, and returns the character array after the signature. The input parameter of the Verifyecdsasig method is the signature, the public key, and the data that needs to be encrypted, and returns TRUE or False when the method is invoked to indicate whether the signature is valid. Getstringfromkey returns the encoded string of any key.
Let's use the signature method to add Generatesiganature () and Varifiysignature () methods in the transaction class.
Sign all the data we don't want to tamper with. public void Generatesignature (Privatekey privatekey) {String data = Stringutil.getstringfromkey ( Sender) + stringutil.getstringfromkey (reciepient) + float.tostring (value); Signature = Stringutil.applyecdsasig (privatekey,data); //Verify that our signed data has not been skipped public boolean verifiysignature () {String data = Stringutil.getstringfromkey (sender) + STRINGUTIL.G Etstringfromkey (reciepient) + float.tostring (value); Return Stringutil.verifyecdsasig (sender, data, signature); }
In the actual business logic process, we will sign more messages (such as the used input output and timestamp, etc.).
The miners will verify the signature, and only a new transaction can be added to the block after the signature verification succeeds.
Step three, test transactions and signatures
Now we're going to simply do some testing, and in the main method, we've added some new variables to replace some of the content in our main method.
Import java.security.Security import java.util.ArrayList import java.util.Base64; import Com.google.gson.GsonBuilder;
public class Noobchain {public static arraylist<block> blockchain = new arraylist<block> (), public Stati c int difficulty = 5; public static Wallet Walleta; public static Wallet Walletb; public static void Main (string[] args) {//Call Bouncey Castle as a security-provided class Security.addprovider (new Org.bouncycastle.jce.provider.BouncyCastleProvider ()); Create two wallets Walleta = new Wallet (); WALLETB = new Wallet (); Test the public and private key System.out.println ("Private and Public Keys:"); System.out.println (Stringutil.getstringfromkey (Walleta.privatekey)); System.out.println (Stringutil.getstringfromkey (Walleta.publickey)); Create a transaction from Walleta address to WALLETB address Transaction Transaction = new Transaction (Walleta.publickey, Walletb.publickey, 5, NULL);
Signing Transaction.generatesignature (Walleta.privatekey) with Wallecta's private key; Verifies that the signature is working System.out.println ("is signature verified") through the Wallecta public key; System.out.println (Transaction.verifiysignature ()); }
So we created two wallets, and the public and private keys of two wallets, and created a transaction, and your output would look like the following figure.
Next we will create and validate input and output, and save the transaction to the block chain.
Fourth step, input and Output 1: How to prove that the encrypted currency belongs to you.
For example: When you have a bitcoin, you have to receive a bitcoin before, and a Bitcoin account will not add a bitcoin to your accounts nor subtract a bitcoin from the sender, the sender can only point to him or her before receiving a bitcoin, So a transaction output is created to display the address that a bitcoin sends to you (the input of the transaction points to the output of the previous transaction).
the balance of your account is the output of all the unused transactions that point to you.
From this point, we will follow the instructions in the Bitcoin to call all unused transaction output Utxo
Let's create a transaction input class (Transactioninput)
public class Transactioninput {public String transactionoutputid;//point to Transaction output class-> TransactionID public transactionoutput Utxo; Contains all unused transaction output public transactioninput (String transactionoutputid) {this.transactionoutputid = Transactionoutputid;}}
Then add one more transaction output class (Transactionoutput)
Import Java.security.PublicKey;
IC String Parenttransactionid; Transaction number//Builder public transactionoutput (PublicKey reciepient, float value, String parenttransactionid) {this.reciepient = R Eciepient; This.value = value; This.parenttransactionid = Parenttransactionid; This.id = stringutil.applysha256 (Stringutil.getstringfromkey (reciepient) +float.tostring (value) + Parenttransactionid); //To verify that it belongs to you public boolean ismine (PublicKey publickey) {return (PublicKey = = reciepient);}
The output of the transaction will show the final amount to be sent to each party from the transaction, thus being referenced in the new transaction and not entered as a proof of the amount of money you can send.
Fifth step, input and Output 2: Transaction processing
The blocks in the chain will receive a lot of transaction information, so the block chain will be very, very long, which will take a long time to deal with a new deal because we have to look for and check its input, in order to bypass this we have saved an additional set called for the use of the transaction as an available input, So adding a set in the main function is called Utxo.
public class Noobchain {public static arraylist<block> blockchain = new arraylist<block> (), public static has hmap<string,transactionoutputs> Utxos = new hashmap<string,transactionoutputs> (); Unused output set public static int difficulty = 5; public static Wallet Walleta; public static Wallet Walletb;
public static void Main (string[] args) {
It's time to get back to business and let's add a Processtransaction method to the trading class, which is to put everything together to deal with the transaction.
//Returns a Boolean value to indicate whether the new intersection was created public boolean processtransaction () {//Verify signature if (Verifiysignature () = False) {SYSTEM.OUT.P Rintln ("#Transaction Signature failed to verify"); return false; //Collect transaction input (note that input is not used) for (Transactioninput i:inputs) {I.utxo = NoobChain.UTXOs.get (I.transactionoutputid);}
//Check if the transaction is valid if (Getinputsvalue () < noobchain.minimumtransaction) {System.out.println ("#Transaction inputs to Small: "+ getinputsvalue ()); return false; //Create the transaction output