Original: How to Write, Deploy, and Interact with Ethereum Smart contracts on a Private Blockchain
Author: Jack_schultz
No, I'm flying.
Abstract: The author gives a very long length of the complete code, related details steps, user interface, etc. of the smart contracts that are written, deployed, and interacted with Ethereum on a private blockchain. The author hopes that with this article, we can write and deploy a smart contract on the private Ethereum blockchain, which is recommended to open with the PC side , and the following is the translation.
The rule here is that if you read through this article, you must deploy a smart contract on your own private ethereum blockchain. All the code I use is given on GitHub, so you have no reason not to.
But if you don't follow the rules and just want to read it, hopefully this will help provide a perspective on how to make a blockchain application from scratch.
Finally, you'll create a private ethereum blockchain, connect two different nodes as peers, write and compile a smart contract, have a Web interface that allows users to ask questions, deploy problems on the blockchain, and then let the user answer.
If you're confused, have an error, or want to say something else, write a comment, get in touch with Twitter, or make a comment.
This is GitHub's repo, so go ahead and fork it (if you don't want to copy and paste all the code), and if you have an update that you want to share, I'll put it in the Readme file. private block chain creation
To create a separate node, you need the following Genesis.json code, which represents the initial block on the private block chain.
Genesis.json
{
"Alloc": {},
"config": {
"Chainid": "
Homesteadblock": 0,
"Eip155block ": 0,
" Eip158block ": 0
},
" nonce ":" 0x0000000000000000 ",
" difficulty ":" 0x4000 ",
" Mixhash ":" 0x0000000000000000000000000000000000000000000000000000000000000000 ",
" Coinbase ":" 0x0000000000000000000000000000000000000000 ",
" timestamp ":" 0x00 ",
" Parenthash ":" 0x0000000000000000000000000000000000000000000000000000000000000000 ",
" Extradata ":" 0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa ",
" Gaslimit ":" 0xFFFFFFFF "
}
If you want a complete explanation of the field, look at the solution to the stack overflow. The difficulty in this case is very low, because you do not want to wait a long time on the test network, chunks can be dug out, and then the value of Gaslimit is high enough to allow a node in the chunk to do the work to handle each transaction.
To open a terminal, make sure that the Geth (Ethereum client) is installed in any way applicable to your operating system, and then CD (DOS command) to the folder where the Genesis.json is saved. Run the following command to initialize the blockchain for that node.
$ geth--datadir "/users/username/library/priveth" Init Genesis.json
-datadir Specifies the location of all data in the blockchain. On Mac operating systems, the default is the ~/library/ethereum directory. Because multiple nodes are running, they cannot be shared with the same data folder, so they need to be specified. Linux and Windows machines have different default datadir, so see where these data should generally be located.
After running the init command with the Genesis.json file, check the--datadir directory and see a bunch of files, so feel free to look around. It's not necessary now, but we'll have to look at it eventually.
For such a blockchain, multiple nodes are required. To make the blockchain a peers, they need to have the same founding file. So to run from the same directory and the same command above, but this time using a different datadir.
Geth--datadir "/users/username/library/priveth2" Init Genesis.json
All the code here will work in the same directory. The code is the same, but with command-line options, these processes can be distinguished by command-line arguments.
Initializes a chain of two nodes.
When running Geth through a different--datadir, a separate node will run regardless of where the command is run. Just remember to specify--datadir every time, then it will not return to the default value. Also note that I changed the names of these datadirs, so I see different names in the screenshot. Open the console
So far, three things have been done. 1) Create a Genesis.json file in the selected working directory, 2) Select a directory storage blockchain for one node and initialize the first chunk, 3) Select a different directory storage blockchain for another node. Little code and some commands.
The next step is to log on to each node's Geth console. The console will start the Geth process and run it, as well as a way to run some WEB3 commands on the terminal.
Geth--datadir "/users/jackschultz/library/ethprivlocal"--networkid--port 30301--nodiscover Console
There are more options here.
-networkid Similar to the Genesis.json file, what you need to do here is to make sure that you do not use network ID 1-4.
-port Specifies the port to which the. ipc file will be used. This is how the database is connected using the Web3.js library, and the default port is 30303. So keep it in that area, but this is the first node, so its port is 30301.
Nodiscover told Geth not to find peers at first. This is really important in this case. This is a private network. You do not want the nodes to attempt to connect to other nodes without specifying them, and you do not want these nodes to be discovered without telling them.
In the case where the first Geth node is running, the same command is run at a different terminal with a second-datadir, and the node runs on a different port.
Start the console. Create an initial Coinbase account for each node
When you run the console with the command above, you want to create the primary Coinbase account. If you're curious, use the passphrase "passphrase" and the node application will use "passphrase" in the future.
> personal.listaccounts
[]
> Personal.newaccount ()
Passphrase:
Repeat Passphrase:
0x538341f72db4b64e320e6c7c698499ca68a6880c
> Personal.listaccounts
[" 0x538341f72db4b64e320e6c7c698499ca68a6880c "]
Run the same command in the console of another node.
Create a new account.
Since this is the first account created by the node, you will see that it is also listed in
> Eth.coinbase
0x538341f72db4b64e320e6c7c698499ca68a6880c
By running another piece of information that can be crawled on the console
> Personal.listwallets
[{
accounts:[{
address: "0x538341f72db4b64e320e6c7c698499ca68a6880c",
URL: "Keystore:///users/jackschultz/library/ethprivlocal/keystore/ Utc--2017-12-09t16-21-48.056824000z--538341f72db4b64e320e6c7c698499ca68a6880c "
}],
status:" Locked ",
URL: "keystore:///users/jackschultz/library/ethprivlocal/keystore/ Utc--2017-12-09t16-21-48.056824000z--538341f72db4b64e320e6c7c698499ca68a6880c "
}]
There you will see more information about the account, not just the address. You will also see where the account information is stored, and it will be in the specified--datadir. So if you're still curious about how the data is stored in the file system, check out the directory. connecting nodes with peers
Multiple nodes are running and need to be peers to connect them. First check if we have peers.
> Admin.peers
[]
So sad. This is what we expect, to start the console on a flag other than 1-4 network ID and nodiscover. This means that each node needs to be told to connect to another node with a specific command. Do this by sharing the Enode address.
> Admin.nodeInfo.enode
"enode:// 13b835d68917bd4970502b53d8125db1e124b466f6473361c558ea481e31ce4197843ec7d8684011b15ce63def5eeb73982d04425af3a0b6f3437a030 878C8A9 @ [:]:30301 discport = 0 "
This is the Enode information that Geth uses to connect to different nodes, where they can share transactions and successfully tap information.
To use this URL to connect to a node, you need to call the Addpeer function.
If you want to copy the return value from one of the nodes Admin.nodeInfo.enode, run the following command in another node.
> Admin.addpeer ("enode:// 13b835d68917bd4970502b53d8125db1e124b466f6473361c558ea481e31ce4197843ec7d8684011b15ce63def5eeb73982d04425af3a0b6f3437a030 878C8A9 @ [::]:30301. DiscPort = 0 ")
This tells the node how to reach the other node and requests that the other node be connected, and they will all be peers to each other. To test, run the admin.peers command on two nodes, and you will see that they are connected together. The code is as follows:
> Admin.peers
[{
caps: ["ETH/63"],
ID: " 99bf59fe629dbea3cb3da94be4a6cff625c40da21dfffacddc4f723661aa1aa77cd4fb7921eb437b0d5e9333c01ed57bfc0d433b9f718a2c95287d354 2f2e9a8 ",
Name:" geth/v1.7.1-stable-05101641/darwin-amd64/go1.9.1 ",
network: {
localaddress:" [:: 1] : 30301 ",
remoteaddress:" [:: 1]:50042 "
},
protocols: {
ETH: {
difficulty:935232,
Head: "0x8dd2dc7968328c8bbd5aacc53f87e590a469e5bde3945bee0f6ae13392503d17",
version:63
}
}< c15/>}]
To add a peer, just tell one node to connect to another node, and then check the other node, and you'll see the following output:
Peers on peers. Check the balance and dig
Now that the nodes are connected, it's not about the money. Before you start digging, check the balance of the master account.
> eth.getbalance (eth.coinbase)
0
>
Once again so sad. Since this account is not assigned to the founding blocks, it is necessary to start mining these accounts.
In the console, run Miner.start () to start mining for this node, and then run Miner.stop () to stop the mining. In the mining, not only to see the account number of the etheric currency, but also to observe the point-to-point interaction between two nodes.
In the picture below, you will see the balance of the master account for each of the two nodes checked. Then start digging on Node 1, let it run for about 5 seconds, and then stop digging after 7 full chunks. Check the balance on the other side, there are 35 etheric coins, in the console this number represents Wei. On the other node, you will see that it receives information from 7 chunks that were mined from node 1.
Start digging. Trading
Using a smart contract requires a specialized transaction, but before you do that, you know how to create a transaction and send the etheric currency to another account.
On one node, use the Coinbase account and unlock it.
> coinbaseaddress = eth.coinbase
> Personal.unlockaccount (coinbaseaddress)
Unlock Account 0x554585d7c4e5b5569158c33684657772c0d0b7e1
Passphrase:
True
Now copy the address from the Coinbase account of another node and go back to the unlocked account node
> hisaddress = "0x846774a81e8e48379c6283a3aa92e9036017172a"
After this, the Sendtransaction command is a bit simpler.
> eth.sendtransaction ({from:eth.coinbase, to:hisaddress, value:100000000})
INFO [12-09|10:29:36] Submitted Transaction fullhash=0x776689315d837b5f0d9220dc7c0e7315ef45907e188684a6609fde8fcd97dd57 recipient= 0X846774A81E8E48379C6283A3AA92E9036017172A
" 0x776689315d837b5f0d9220dc7c0e7315ef45907e188684a6609fde8fcd97dd57 "
There's one more thing to be aware of, and it's easy to confuse, and that's why these numbers are worth 0 more. This is because the values are represented by Wei, so you do not have to deal with floating-point numbers that may cause problems on different systems. This will be related to gas (a measure roughly equivalent to the calculation step). Each transaction needs to include a gas limit and a fee that is willing to pay for each gas; the miners can choose to trade and charge together, and they need to start specifying contract deployment and trading.
If you want to know how many etheric tokens are sent with this value, the command is as follows:
> Web3.fromwei (100000000, ' ether ')
"0.0000000001"
To send the transaction and see the difference between the different balances, you need to start the miner in the node, then stop after digging a chunk, and now check the balance to see the change.
> Miner.start ()
...... ..... > miner.stop ()
> Web3.eth.getBalance (eth.coinbase)
59999999999900000000
> Web3.eth.getBalance (hisaddress)
100000000
Now take a look at this huge picture below. Similarly, node 1 is on the left and Node 2 is on the right. So first check the balance of the respective Coinbase account on each node. On Node 1, copy the address of Node 2, send the transaction, and then log in from the node that received the transaction that was submitted, and then start digging. You'll find that node 8 has Txs=1, which means it dug up a deal in that block. After digging a few more chunks, stop digging. Check the account balance for node 1. There are 12 blocks, each of which rewards 5 ethereum, but then it pays 100000000wei.
Now, back to Node 2, check the balance of its Coinbase account, the balance is 0. Then, remember to restart the console of the feast point 1, and do not set the two nodes to peers. Therefore, print node 1 of the Enode, as a peer to add it to Node 2. After you add a peer, you'll see that node 2 receives the missing block, including 1 trades. Then check the balance again and find it has 100000000Wei.
This is how to send the etheric currency locally. Intermittent
Almost half of the work has been done here. Works on a terminal with a private ethereum blockchain that runs locally, owns two nodes of the account, is peers to each other, and can send transactions back and forth.
It's pretty good, so it can take a little time to calm down and have a better understanding. But at the moment, please move on. write a contract on the remix
Go on. With the Geth node running, the next step is to sign a contract.
When writing such an article, it takes a long time to choose a simple and valuable example. This is also the case when trying to choose a contract to use. What I decided to put here is that people can answer yes/no or True/false questions.
Below is the final V1 code for solidity (the programming language for developing smart contracts in Ethereum, which currently develops the most solidity) contracts for smart contracts. Before looking at the code, there are a few things to note:
In this example, only global variables are used to solve the problem, who asked the question, who answered the question, and the value of the answer. Solidity also has a structure that can store data, but this article discusses deployment rather than solidity, so don't go too deep.
Use Uints to store yes/no answers, not bools. In solidity, if there is a mapping to link the address to bool, the default value is False. For a uint, the default value is zero. This has the necessary three states, where you can use an enum, but as I said, try to keep it simple.
The Answerquestion method is somewhat complex in both logical and if statements. If you want to learn how to adjust a variable, read it carefully.
There is a get function that returns all the information that you want to show the status of the contract on the page. You can return different information separately, but you might want to put them together without having to query them multiple times.
-There are not only other ways to store this data in the contract, there are many other ways to write it. For example, you can list all accounts that voted true or FALSE, and then loop through them to see if they have been answered.
pragma solidity ^0.4.0; Contract Questions { //global variables, aren ' t in a struct mapping (address-=-UINT) public answers;
Integer where 0 means hasn ' t answered, 1 means yes, 2 means no string question;
address Asker;
uint trues;
uint falses; ///__init__ function Questions (string _question) public { asker = Msg.sender; question = _ques
tion;
} //we need a validate whether or not they ' ve answered before. //the default of a mapping is function answerquestion (bool _answer) public { if (answers[msg.
Sender] = = 0 && _answer) {//haven ' t answered yet answers[msg.sender] = 1;//they vote true
trues + = 1; } else if (answers[msg.sender] = = 0 &&!_answer) { answers[msg.sender] = 2;//f
Alsity falses + = 1; } else if (answers[mSg.sender] = = 2 && _answer) {//False switching to true answers[msg.sender] = 1;//true &nb Sp
trues + = 1;
falses-= 1; } else if (answers[msg.sender] = = 1 &&!_answer) {//true switching to F Alse answers[msg.sender] = 2;
falsity trues-= 1;
falses + = 1; } } function getquestion () public constant Returns (string, uint, uint, uint) {
Return (question, trues, falses, Answers[msg.sender]); }}
Save this contract in Contracts/question.sol instead of compiling locally, using remix to handle a large number of errors and code warnings, and compiling the required information.
To see the compilation information, click the Details button on the Compile tab in the upper-right corner and you'll see a bunch of information pop-up. The data to look for is bytecode and ABI. Below right is the deployment information for the WEB3 to be emulated. However, instead of entering a huge string from a single line, import the information from a JSON file. The data must be separated.
//childcontractv1.json { "ABI": [{"Constant": true, "inputs": [{"Name": "", "type": " Address "}", "Name": "Answers", "outputs": [{"Name": "", "type": "uint256"}], "payable": false, "statemutability": "View", "Type": "function"},{"constant": true, "inputs": [], "name": "Getquestion", "outputs": [{"Name": "", "Type": "String"},{" Name ":", "type": "uint256"},{"name": "", "type": "uint256"},{"name": "", "type": "uint256"}], "payable": false, " Statemutability ":" View "," type ":" function "},{" constant ": false," inputs ": [{" Name ":" _answer "," type ":" BOOL "}]," name ":" Answerquestion "," outputs ": []," payable ": false," statemutability ":" Nonpayable "," type ":" function "},{" inputs ": [{
"Name": "_question", "Type": "string"}], "payable": false, "statemutability": "Nonpayable", "type": "Constructor"}], "bytecode": "0x6060604052341561000f57600080fd5b6040516106d23803806106