以太坊智能合约开发入门


声明:本文转载自https://my.oschina.net/neochen/blog/1618287,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

以太坊智能合约开发入门

本文作者最近在找工作,有意向致电 13113668890

Mr. Neo Chen (陈景峯), netkiller, BG7NYT


中国广东省深圳市龙华新区民治街道溪山美地
518131
+86 13113668890

<netkiller@msn.com>

版权声明

转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。

http://www.netkiller.cn
http://netkiller.github.io
http://netkiller.sourceforge.net
微信订阅号 netkiller-ebook (微信扫描二维码)
QQ:13721218 请注明“读者”
QQ群:128659835 请注明“读者”

 

2018-02-04

摘要

本文采用碎片化写作,原文会不定期更新,请尽量阅读原文。

http://www.netkiller.cn/journal/ethereum.solidity.html

目录

1. Truffle

Truffle 是 solidity 开发框架

1.1. 安装 Truffle

# 安装 Nodejs curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - sudo apt-get install -y nodejs 			 # 安装truffle sudo npm install -g truffle  # 安装testrpc sudo npm install -g ethereumjs-testrpc

1.2. 创建项目

cd ~/ethereum mkdir truffle-project cd truffle-project  truffle init

操作演示

neo@netkiller ~/ethereum/truffle-project % truffle init Downloading... Unpacking... Setting up... Unbox successful. Sweet!  Commands:    Compile:        truffle compile   Migrate:        truffle migrate   Test contracts: truffle test    neo@netkiller ~/ethereum/truffle-project % tree  . |-- contracts |   `-- Migrations.sol |-- migrations |   `-- 1_initial_migration.js |-- test |-- truffle-config.js `-- truffle.js  3 directories, 4 files

1.3. 配置 Truffle

打开文件 truffle.js 

module.exports = {   // See <http://truffleframework.com/docs/advanced/configuration>   // to customize your Truffle configuration! };

修改为

module.exports = {   // See <http://truffleframework.com/docs/advanced/configuration>   // to customize your Truffle configuration! 			   networks: {     development: {       host: "localhost",       port: 8545,       network_id: "*" // Match any network id     }   }	   		 };

1.4. 编译智能合约

neo@netkiller ~/ethereum/truffle-project % truffle compile Compiling ./contracts/Migrations.sol... Writing artifacts to ./build/contracts

truffle默认只会编译最后一次修改过的合约文件, 这是为了减少比重复编译。"--all"选项,可以强制编译所有文件。

编译结果

neo@netkiller ~/ethereum/truffle-project % find build  build build/contracts build/contracts/Migrations.json

1.5. migrate

neo@netkiller ~/ethereum/truffle-project % truffle migrate       Using network 'development'.  Network up to date.

1.6. 部署智能合约

neo@netkiller ~/ethereum/truffle-project % truffle deploy Using network 'development'.  Network up to date.

2. browser-solidity

在线使用 browser-solidity

https://ethereum.github.io/browser-solidity/ https://remix.ethereum.org/

国内网络有时不给力,建议将 Remix 安装到本地目录。

2.1. 将 Remix(browser-solidity) 安装到本地

共享合约目录

npm install -g remixd remixd -S "/home/ethereum/codebase/blocks/contracts"

安装 browser-solidity 

git clone https://github.com/ethereum/browser-solidity  cd browser-solidity  npm install  npm run prepublish  sudo chown -R $USER:$(id -gn $USER) /home/neo/.config  npm start

启动后浏览器中输入 http://localhost:8080 可以看到 Remix 界面

Web3 Provider

Remix 提供三种运行环境,常用的有 JavaScript VM 和 Web3 Provider (连接到 --rpc --rpcaddr="0.0.0.0" --rpccorsdomain "*" --rpcport 8545)

Web3 Provider 方式需要解锁账号和启动挖矿

> personal.unlockAccount(eth.accounts[0],""); > miner.start(2); admin.sleepBlocks(1); miner.stop();

3. 使用 solc 编译 *.sol 代码

neo@netkiller ~/ethereum/solidity % solc --bin --abi --optimize -o ./output helloworld.sol neo@netkiller ~/ethereum/solidity % find output          output output/HelloWorld.bin output/HelloWorld.abi

4. 智能合约语言 Solidity

Solidity 是什么?Solidity是以太坊智能合约的编程语言。

4.1. 智能合约入门演示

这里我们先做一个 Helloword 演示,让你初步对智能合约有一个大概的认识。

提示

需要注意的是,你在网上会看到很多例子,对照这例子一步一步操作,始终无法成功,这根Solidity的版本有很大关系。

将下面代码粘贴到 

pragma solidity ^0.4.19;  contract HelloWorld {     string tmp;      function HelloWorld() public     {      }      function get() public constant returns (string)     {         return tmp;     }      function set(string _tmp) public     {         tmp = _tmp;     }  }

Compile - Details - WEB3DEPLOY

var helloworldContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"_tmp","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]); var helloworld = helloworldContract.new(    {      from: web3.eth.accounts[0],       data: '0x6060604052341561000f57600080fd5b6102e38061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100515780636d4ce63c146100ae575b600080fd5b341561005c57600080fd5b6100ac600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061013c565b005b34156100b957600080fd5b6100c1610156565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101015780820151818401526020810190506100e6565b50505050905090810190601f16801561012e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101529291906101fe565b5050565b61015e61027e565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101f45780601f106101c9576101008083540402835291602001916101f4565b820191906000526020600020905b8154815290600101906020018083116101d757829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023f57805160ff191683800117855561026d565b8280016001018555821561026d579182015b8281111561026c578251825591602001919060010190610251565b5b50905061027a9190610292565b5090565b602060405190810160405280600081525090565b6102b491905b808211156102b0576000816000905550600101610298565b5090565b905600a165627a7a72305820ea826c30d131f20a4d3a8e3fb059ffa95f4c222a5b099029750e4c1937b46e5b0029',       gas: '4700000'    }, function (e, contract){     console.log(e, contract);     if (typeof contract.address !== 'undefined') {          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);     }  })

部署智能合约需要消耗 gas 所以你要先解锁账号。

> personal.unlockAccount("0x83fda0ba7e6cfa8d7319d78fa0e6b753a2bcb5a6", "", 300) true
> var helloworldContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"_tmp","type":"string"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]); undefined > var helloworld = helloworldContract.new( ...    { ......      from: web3.eth.accounts[0],  ......      data: '0x6060604052341561000f57600080fd5b6102e38061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100515780636d4ce63c146100ae575b600080fd5b341561005c57600080fd5b6100ac600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509190505061013c565b005b34156100b957600080fd5b6100c1610156565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101015780820151818401526020810190506100e6565b50505050905090810190601f16801561012e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b80600090805190602001906101529291906101fe565b5050565b61015e61027e565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101f45780601f106101c9576101008083540402835291602001916101f4565b820191906000526020600020905b8154815290600101906020018083116101d757829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061023f57805160ff191683800117855561026d565b8280016001018555821561026d579182015b8281111561026c578251825591602001919060010190610251565b5b50905061027a9190610292565b5090565b602060405190810160405280600081525090565b6102b491905b808211156102b0576000816000905550600101610298565b5090565b905600a165627a7a72305820ea826c30d131f20a4d3a8e3fb059ffa95f4c222a5b099029750e4c1937b46e5b0029',  ......      gas: '4700000' ......    }, function (e, contract){ ......     console.log(e, contract); ......     if (typeof contract.address !== 'undefined') { .........          console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); .........     } ......  }) null [object Object] undefined

helloworld 智能合约已经创建完毕

> helloworld {   abi: [{       constant: false,       inputs: [{...}],       name: "set",       outputs: [],       payable: false,       stateMutability: "nonpayable",       type: "function"   }, {       constant: true,       inputs: [],       name: "get",       outputs: [{...}],       payable: false,       stateMutability: "view",       type: "function"   }, {       inputs: [],       payable: false,       stateMutability: "nonpayable",       type: "constructor"   }],   address: undefined,   transactionHash: "0x466c9ad9db8f37ed5b65bc261210da92f51364ebab1dcbd3759bfc3e16ad6502" }

4.2. 修饰符

public : 函数可见性  payable :可支付的函数修饰符,没有该修饰符无法接受转账操作。  msg.value :执行合约时,转账的eth数量,以wei为单位。  msg.sender : 执行合约的地址

4.3. 数据类型



uint 无符号整形(256bits 无符号整数)
string 字符串类型
 

4.3.1. 数组

//创建一个memory的数组 	uint[] memory a = new uint[](7); 	 	uint[] x = [uint(1), 3, 4];

4.3.2. 枚举类型

pragma solidity ^0.4.0;  contract Purchase {     enum State { Created, Locked, Inactive } // Enum }

4.3.3. 结构体

定义结构体

struct Voter {         uint weight; // weight is accumulated by delegation         bool voted;  // if true, that person already voted         address delegate; // person delegated to         uint vote;   // index of the voted proposal     }      // This is a type for a single proposal.     struct Proposal {         bytes32 name;   // short name (up to 32 bytes)         uint voteCount; // number of accumulated votes     }

4.4. 变量

address public minter; string name; int num;	      uint constant x = 32**22 + 8;     string constant text = "abc";     bytes32 constant myHash = keccak256("abc");          uint256 ticket = 1 ether;

变量赋值

pragma solidity ^0.4.19;  contract C {     uint[] data;      function f() public view returns (uint, bool, uint) {         return (7, true, 2);     }      function g() public {         // 声明和分配变量。 明确指定类型是不可能的。         var (x, b, y) = f();         // 分配给一个预先存在的变量。         (x, y) = (2, 7);         // 互换值的常用技巧对于非价值存储类型不起作用。         (x, y) = (y, x);         // 组件可以省略(也可以用于变量声明)。         // 如果元组以空组件结束,其余的值将被丢弃。         (data.length,) = f(); // 设置长度为 7         // 在左边也可以做同样的事情。         (,data[3]) = f(); // Sets data[3] to 2         // 组件只能在作业的左侧排除,但有一个例外:         (x,) = (1,);         // (1,) 是指定1元组元的唯一方法,因为(1)等于1。     } }

4.5. 函数

4.5.1. 构造方法

构造方法的定义是 contract 与 function 相同

pragma solidity ^0.4.18;  contract MyContractByNetkiller {     /* Constructor */      function MyContractByNetkiller() public{      } }

4.5.2. 定义函数

没有返回值

function setName(string _name) public{         name = _name;     }

4.5.3. 函数返回值

有返回值

function getName() public view returns(string){         return name;     }

4.5.4. 参数传递

除了 f(2,3) 这样传递参数,还可以使用类似字典或Map的方式 f({value: 2, key: 3});

pragma solidity ^0.4.0;  contract C {     function f(uint key, uint value) {         // ...     }      function g() {         // named arguments         f({value: 2, key: 3});     } }

4.5.5. 函数的例子

完整的例子

pragma solidity ^0.4.18;  contract MyContractByNetkiller {     /* Constructor */     string name;     int num;     function MyContractByNetkiller() public{         name = "default";         num = 1;     }     function setName(string _name) public{         name = _name;     }     function getName() public view returns(string){         return name;     }     function setNum(int n) public{         num = n;     }     function addNum(int m) public view returns(int res){         res = m + num;     } }

4.6. 事件

event Sent(address from, address to, uint amount);

5. Jave Client

官方网站 https://web3j.io

Java 客户端与 Server 之间采用json-rpc协议连接。

5.1. 安装命令行工具

web3j 命令用于将 sol 合约文件转换为 java 文件。

5.1.1. Mac OS

brew tap web3j/web3j brew install web3j  neo@MacBook-Pro ~ % web3j                _      _____ _     _                      | |    |____ (_)   (_)        __      _____| |__      / /_     _   ___   \ \ /\ / / _ \ '_ \     \ \ |   | | / _ \   \ V  V /  __/ |_) |.___/ / | _ | || (_) |   \_/\_/ \___|_.__/ \____/| |(_)|_| \___/                           _/ |                                      |__/                Usage: web3j version|wallet|solidity ...

5.1.2. 二进制包安装

下载二进制文件 https://github.com/web3j/web3j/releases

wget https://github.com/web3j/web3j/releases/download/v3.2.0/web3j-3.2.0.zip unzip web3j-3.2.0.zip  $ ./web3j-3.2.0/bin/web3j                _      _____ _     _              | |    |____ (_)   (_) __      _____| |__      / /_     _   ___ \ \ /\ / / _ \ '_ \     \ \ |   | | / _ \  \ V  V /  __/ |_) |.___/ / | _ | || (_) |   \_/\_/ \___|_.__/ \____/| |(_)|_| \___/                          _/ |                         |__/  Usage: web3j version|wallet|solidity ...

5.2. 启动以太坊

首先启动服务

neo@netkiller ~ % geth --networkid 123456 --rpc --rpcaddr="0.0.0.0" --rpccorsdomain "*" --nodiscover  INFO [02-01|23:35:12] Starting peer-to-peer node               instance=Geth/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9.1 INFO [02-01|23:35:12] Allocated cache and file handles         database=/home/neo/.ethereum/geth/chaindata cache=128 handles=1024 INFO [02-01|23:35:12] Initialised chain configuration          config="{ChainID: 15 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Engine: unknown}" INFO [02-01|23:35:12] Disk storage enabled for ethash caches   dir=/home/neo/.ethereum/geth/ethash count=3 INFO [02-01|23:35:12] Disk storage enabled for ethash DAGs     dir=/home/neo/.ethash               count=2 INFO [02-01|23:35:12] Initialising Ethereum protocol           versions="[63 62]" network=123456 INFO [02-01|23:35:12] Loaded most recent local header          number=719 hash=61330b…82786e td=108754979 INFO [02-01|23:35:12] Loaded most recent local full block      number=719 hash=61330b…82786e td=108754979 INFO [02-01|23:35:12] Loaded most recent local fast block      number=719 hash=61330b…82786e td=108754979 INFO [02-01|23:35:12] Loaded local transaction journal         transactions=0 dropped=0 INFO [02-01|23:35:12] Regenerated local transaction journal    transactions=0 accounts=0 WARN [02-01|23:35:12] Blockchain not empty, fast sync disabled  INFO [02-01|23:35:12] Starting P2P networking  INFO [02-01|23:35:12] RLPx listener up                         self="enode://9f6490ffb5236f2ddc5710ae73d47c740e0a3644bbd2d67029cf4a6c4693d2f470b642fd2cc3507f7e851df60aaeb730a1270b7a477f91ec5b6b17a8a4b40527@[::]:30303?discport=0" INFO [02-01|23:35:12] IPC endpoint opened: /home/neo/.ethereum/geth.ipc  INFO [02-01|23:35:12] HTTP endpoint opened: http://0.0.0.0:8545  INFO [02-01|23:35:15] Mapped network port                      proto=tcp extport=30303 intport=30303 interface="UPNP IGDv1-IP1"

Web3j 将使用这个地址连接 HTTP endpoint opened: http://your_ip_address:8545

5.3. Maven pom.xml 文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 	<modelVersion>4.0.0</modelVersion>  	<groupId>cn.netkiller</groupId> 	<artifactId>ethereum</artifactId> 	<version>0.0.1-SNAPSHOT</version> 	<packaging>jar</packaging>  	<name>ethereum</name> 	<url>http://maven.apache.org</url>  	<properties> 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 	</properties>  	<dependencies> 		<dependency> 			<groupId>org.web3j</groupId> 			<artifactId>core</artifactId> 			<version>3.2.0</version> 		</dependency> 	</dependencies> </project>

5.4. Java 与 Solidity 数据类型映射关系

boolean -> bool BigInteger -> uint/int byte[] -> bytes String -> string and address types List<> -> dynamic/static array

5.5. 连接到服务器获取版本号

package cn.netkiller.ethereum;  import java.io.IOException;  import org.web3j.protocol.Web3j; import org.web3j.protocol.core.methods.response.Web3ClientVersion; import org.web3j.protocol.http.HttpService;  public class Web3JClient { 	// TODO Auto-generated method stub  	public static void main(String[] args) { 		String url = "http://172.16.0.1:8545/"; 		Web3j web3j = Web3j.build(new HttpService(url)); // defaults to http://localhost:8545/  		try { 			Web3ClientVersion web3ClientVersion = web3j.web3ClientVersion().send(); 			String clientVersion = web3ClientVersion.getWeb3ClientVersion(); 			System.out.println(clientVersion); 		} catch (IOException e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		}  	}  }

运行结果

Geth/v1.7.3-stable-4bb3c89d/linux-amd64/go1.9.1

除了 TCP 方式连接,还支持 IPC 方式。这种方式比较少用,可以使用 localhost 替代。

// OS X/Linux/Unix: Web3j web3 = Web3j.build(new UnixIpcService("/path/to/socketfile")); ...  // Windows Web3j web3 = Web3j.build(new WindowsIpcService("/path/to/namedpipefile")); ...

5.6. 账号管理

5.6.1. 获得账号列表

public List<String> getAccountlist() {  		try { 			return web3j.ethAccounts().send().getAccounts(); 		} catch (Exception e) { 			e.printStackTrace(); 		} 		return null; 	}

5.6.2. 获得账号信息

public String getAccount(int index) { 		String account = null;  		try { 			account = web3j.ethAccounts().send().getAccounts().get(index);  		} catch (IOException e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		} 		return account; 	}

5.6.3. 解锁账号

Admin web3j = Admin.build(new HttpService());  // defaults to http://localhost:8545/ PersonalUnlockAccount personalUnlockAccount = web3j.personalUnlockAccount("0x000...", "a password").sendAsync().get(); if (personalUnlockAccount.accountUnlocked()) {     // send a transaction }

5.6.4. 例子

5.7. Credentials

package cn.netkiller.ethereum.credentials;  import java.io.IOException; import java.math.BigInteger;  import org.web3j.crypto.Credentials; import org.web3j.crypto.ECKeyPair; import org.web3j.protocol.Web3j; import org.web3j.protocol.http.HttpService;  public class CredentialsTest {  	public static void main(String[] args) { 		// TODO Auto-generated method stub  		String url = "http://172.16.0.1:8545/"; 		Web3j web3j = Web3j.build(new HttpService(url)); // defaults to http://localhost:8545/  		try { 			String account = web3j.ethAccounts().send().getAccounts().get(0); 			Credentials credentials = Credentials.create(account); 			ECKeyPair keyPair = credentials.getEcKeyPair(); 			BigInteger privateKey = keyPair.getPrivateKey(); 			BigInteger publicKey = keyPair.getPublicKey();  			System.out.println(privateKey); 			System.out.println("---"); 			System.out.println(publicKey); 		} catch (IOException e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		}  	}  }

5.8. 交易

5.8.1. 获取余额

public BigInteger getBalance(String account) throws IOException {  		EthGetBalance ethGetBalance = web3j.ethGetBalance(account, DefaultBlockParameterName.LATEST).send(); 		BigInteger balance = ethGetBalance.getBalance(); 		return balance;  	}

5.8.2. 转账

public void transfer(String account, float coin) 			throws InterruptedException, IOException, TransactionException, Exception { 		String password = ""; 		String walletfile = "/Users/neo/netkiller/UTC--2018-01-20T04-04-06.786586541Z--83fda0ba7e6cfa8d7319d78fa0e6b753a2bcb5a6"; 		Credentials credentials = WalletUtils.loadCredentials(password, walletfile); 		TransactionReceipt transactionReceipt = Transfer 				.sendFunds(web3j, credentials, account, BigDecimal.valueOf(coin), Unit.ETHER).send(); 		System.out.println(transactionReceipt.getStatus()); 	}

5.8.3. 交易结果查询

EthTransaction transaction = web3.ethGetTransactionByHash("TRANSACTION_HASH")                                    .sendAsync().get(); System.out.println(transaction.getResult());

5.9. 钱包

5.9.1. 创建钱包

package cn.netkiller.ethereum.wallet;  import java.io.File; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException;  import org.web3j.crypto.CipherException; import org.web3j.crypto.WalletUtils;  public class WalletMain {  	public void createWallet() throws NoSuchAlgorithmException, NoSuchProviderException, 			InvalidAlgorithmParameterException, CipherException, IOException {  		File file = new File("/tmp/ethereum/keystore"); 		String password = "passw0rd"; 		String fileName = WalletUtils.generateFullNewWalletFile(password, file); 		System.out.println(fileName);  	}  	public static void main(String[] args) { 		// TODO Auto-generated method stub 		WalletMain wallet = new WalletMain(); 		try { 			wallet.createWallet(); 		} catch (Exception e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		}  	} }

运行结果

neo@MacBook-Pro ~ % mkdir -p /tmp/ethereum/keystore neo@MacBook-Pro ~ % ll /tmp/ethereum/keystore total 8 -rw-r--r--  1 neo  wheel   491B Feb  4 18:30 UTC--2018-02-04T10-30-58.476000000Z--75d01e920d6e018445dae504058ce4d968fd2a58.json  neo@MacBook-Pro ~ % cat /tmp/ethereum/keystore/UTC--2018-02-04T10-30-58.476000000Z--75d01e920d6e018445dae504058ce4d968fd2a58.json  {"address":"75d01e920d6e018445dae504058ce4d968fd2a58","id":"80700448-69bc-475a-aaf9-f2b836f17b13","version":3,"crypto":{"cipher":"aes-128-ctr","ciphertext":"fe86f5dbd61d15d092f9d6870e70bff7ed99a7925703ea71eef23669c8e3ec62","cipherparams":{"iv":"d058819ab660cd062080b405591ba143"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"f69c535137b08667dbac53b8001313f5b43f81fce67a5d0e94b518c97d212d14"},"mac":"c247e34760bc838c3a4c8b2da286ccc6acec244bbc13fc6cc9ce28e88a7319d5"}}

5.9.2. 从钱包取出账号

package cn.netkiller.ethereum.wallet;  import java.io.File; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException;  import org.web3j.crypto.CipherException; import org.web3j.crypto.Credentials; import org.web3j.crypto.WalletUtils;  public class WalletMain {  	public void walletAddress() throws IOException, CipherException {  		File file = new File( 				"/tmp/ethereum/keystore/UTC--2018-02-04T10-43-27.339000000Z--7cab470df532710d13078c5cdc0812a27f70cf51.json"); 		String password = "passw0rd"; 		Credentials credentials = WalletUtils.loadCredentials(password, file); 		System.out.println(credentials.getAddress());  	}  	public static void main(String[] args) { 		// TODO Auto-generated method stub 		WalletMain wallet = new WalletMain(); 		try { 			wallet.walletAddress(); 		} catch (Exception e) { 			// TODO Auto-generated catch block 			e.printStackTrace(); 		}  	} }

运行结果

0x7cab470df532710d13078c5cdc0812a27f70cf51

5.10. 智能合约

neo@netkiller ~/ethereum/solidity % cat netkiller.sol  pragma solidity ^0.4.18;  contract Netkiller {     string name;     int num;     function Netkiller() public{         name = "default";         num = 1;     }     function setName(string _name) public{         name = _name;     }     function getName() public view returns(string){         return name;     }     function setNum(int n) public{         num = n;     }     function addNum(int m) public view returns(int res){         res = m + num;     } }

编译智能合约

$ solc /path/to/<smart-contract>.sol --bin --abi --optimize -o output/ $ web3j solidity generate /path/to/<smart-contract>.bin /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name
$ solc netkiller.sol --bin --abi --optimize -o output/ $ web3j solidity generate output/Netkiller.bin output/Netkiller.abi -p cn.netkiller.ethereum.contract -o java                _      _____ _     _                      | |    |____ (_)   (_)        __      _____| |__      / /_     _   ___   \ \ /\ / / _ \ '_ \     \ \ |   | | / _ \   \ V  V /  __/ |_) |.___/ / | _ | || (_) |   \_/\_/ \___|_.__/ \____/| |(_)|_| \___/                           _/ |                                      |__/                Generating cn.netkiller.ethereum.contract.Netkiller ... File written to java	  neo@netkiller ~/ethereum/solidity % ll java/cn/netkiller/ethereum/contract/Netkiller.java  -rw-rw-r-- 1 neo neo 5.9K Feb  3 23:02 java/cn/netkiller/ethereum/contract/Netkiller.java

启动以太坊,并开始挖矿。注意参数 --mine --minerthreads 1 ,你也可以启动后在JavaScript 控制台钟启动挖矿。

neo@netkiller ~ % geth --networkid 123456 --rpc --rpcaddr="0.0.0.0" --rpccorsdomain "*" --mine --minerthreads 1
package cn.netkiller.ethereum;  import java.math.BigInteger;  import org.web3j.crypto.Credentials; import org.web3j.crypto.WalletUtils; import org.web3j.protocol.Web3j; import org.web3j.protocol.http.HttpService; import org.web3j.tx.Contract; import org.web3j.tx.ManagedTransaction;  import cn.netkiller.ethereum.contract.Netkiller;  public class ContractTest {  	public static void main(String[] args) throws Exception { 		// TODO Auto-generated method stub  		String walletfile = "/Users/neo/Downloads/UTC--2018-01-20T04-04-06.786586541Z--83fda0ba7e6cfa8d7319d78fa0e6b753a2bcb5a6";  		Web3j web3j = Web3j.build(new HttpService("http://172.16.0.1:8545")); 		Credentials credentials = WalletUtils.loadCredentials("", walletfile);  		Netkiller contract = Netkiller.deploy(web3j, credentials, ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT).send();  		System.out.println(contract.isValid()); 		if (contract.isValid()) { 			System.out.println("---"); 			String contractAddress = contract.getContractAddress(); 			System.out.println(contractAddress); 			System.out.println("---"); 			String result = contract.getName().send(); 			System.out.println(result);  			contract.setName("Netkiller").send(); 			System.out.println(contract.getName().send()); 			System.out.println("---"); 			contract.setNum(BigInteger.valueOf(8)).send(); 			System.out.println(contract.addNum(BigInteger.valueOf(8)).send()); 			System.out.println("---"); 		} else { 			System.out.println("Deploy ERROR !!!"); 		} 	}  }

运行结果

true --- 0xef872f1b344a4b7c765c7d765a3cc82b741777a9 --- default Netkiller --- 16 ---

在程序运行是,去看 geth 打印的日志,有如下记录打印

INFO [02-04|00:04:43] Submitted transaction                    fullhash=0x9f70ccb600294d2dd6dda08d090362131b107d42a692f27dd4a3b7548dbaf22c recipient=0xEF872F1b344a4B7C765c7D765a3cC82b741777a9

5.10.1. 载入合约

HelloWorld contract = HelloWorld.load(contractAddress,web3j,credentials, ManagedTransaction.GAS_PRICE, Contract.GAS_LIMIT);
 

6. web3.py - A python interface for interacting with the Ethereum blockchain and ecosystem.

文档地址 http://web3py.readthedocs.io/

 

 

本文发表于2018年02月04日 22:37
(c)注:本文转载自https://my.oschina.net/neochen/blog/1618287,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1919 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1