从私有区块链搭建到部署智能合约再到java调用操作步骤

文章目录

      • 一、搭建私有链
        • 1. 创世json文件: genesis.json
        • 2. 创建区块链节点: dataChain
          • 2.1 错误与常见问题
        • 3. 启动服务端: dataChainServer
        • 4. 启动客户端: dataChainClient
        • 5. 客户端设置挖矿账户
          • 5.1 常见问题
      • 二、部署智能合约
        • 1. 合约代码
        • 2. 编译合约
        • 3. 部署合约
          • 3.1 常见问题
      • 三、Java 通过web3j 调用智能合约
        • 1. 将web3j编译生成的java合约文件拷贝到工程中
        • 2. web3j 工具类连接区块链
        • 3. 调用智能合约里的方法

一、搭建私有链

1. 创世json文件: genesis.json

{
    "config":{
        "chainId":15,
        "homesteadBlock":0,
        "eip155Block":0,
        "eip158Block":0
    },
    "difficulty":"4",
    "gasLimit":"2100000",
    "alloc":{ }
}

2. 创建区块链节点: dataChain

geth init genesis.json --datadir dataChain
2.1 错误与常见问题

<1>错误1:pcscd服务错误

如果初始化节点过程中报以下错误:

INFO [11-09|17:23:10.229] Smartcard socket not found, disabling    err="stat /run/pcscd/pcscd.comm: no such file or directory"

则后面会挖不出来矿,需要安装pscd服务

sudo apt-get -y install libusb-dev
sudo apt-get -y install pcscd

<2>错误2:创世文件block

如果初始化节点过程中报以下错误:

Fatal: Failed to write genesis block: unsupported fork ordering: eip150Block not enabled, but eip155Block enabled at 0

则修改创世文件block号150和155:

"eip150Block": 0,
"eip155Block": 0

3. 启动服务端: dataChainServer

# geth --networkid 123 --datadir dataChain --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --port 3000 --allow-insecure-unlock

备注:

  • rpcaddr 可以写本机地址,也可以写127.0.0.1
  • 如果这里的rpcaddr 和 rpcport 修改为其他值了,则需要修改程序里web3j连接的url
  • 加上 --allow-insecure-unlock 防止解锁账户过程中出错;

4. 启动客户端: dataChainClient

# cd dataChain
# geth attach ipc:geth.ipc

5. 客户端设置挖矿账户

# geth attach ipc:geth.ipc
> personal.listAccounts
[]
> personal.newAccount("123456")
"0x0f6740d209db6ed6b12c70daf667340cd06c5611"
> personal.listAccounts
["0x0f6740d209db6ed6b12c70daf667340cd06c5611"]
> eth.getBalance(personal.listAccounts[0])
0
> miner.setEtherbase(personal.listAccounts[0])
true
> miner.start()
null
> miner.stop()
null
> eth.getBalance(personal.listAccounts[0])
35000000000000000000

说明:

  • 创建账户过程中newAccount()方法传递的参数即是该账户的密码(如:“123456”)
5.1 常见问题

<1> 首次挖矿需要等待较长时间

  • 一台计算机创建完节点首次挖矿时需要等待较长时间,Generating DAG in progress需要从0%到100%

二、部署智能合约

1. 合约代码

pragma solidity ^0.4.4;
contract CheckContract {
    
    function check(string attributeA, string attributeB) pure public returns(bool){
		if(bytes(attributeA).length != bytes(attributeB).length){
			return false;
		}else{
			return keccak256(bytes(attributeA)) == keccak256(bytes(attributeA));
		}
    }
}

2. 编译合约

# 编译合约,生成bin文件
solc --bin CheckContract.sol -o ./

# 编译合约,生成abi文件
solc --abi CheckContract.sol -o ./

// web3j 根据bin文件和abi文件生成Java合约类
web3j solidity generate --javaTypes --binFile=CheckContract.bin --abiFile=CheckContract.abi -o ./ --package='myContract'

3. 部署合约

#! dataChainClient

# 合约bin赋值,拷贝.bin文件里的值
# 记得在.bin文件的值之前加 0x
>var publicBinCode="0x608060405234801561001057600080fd5b50610227806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063725dbc4014610046575b600080fd5b34801561005257600080fd5b506100f3600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061010d565b604051808215151515815260200191505060405180910390f35b60008151835114151561012357600090506101f5565b816040518082805190602001908083835b6020831015156101595780518252602082019150602081019050602083039250610134565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916836040518082805190602001908083835b6020831015156101c0578051825260208201915060208101905060208303925061019b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019161490505b929150505600a165627a7a7230582096b45b9571ed5dacf868e454b6330fa960d7099f595bd758e940a49bd7ec68790029"

# 合约 abi赋值
 >var publicAbiCode=[{"constant":true,"inputs":[{"name":"attributeA","type":"string"},{"name":"attributeB","type":"string"}],"name":"check","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"}]
 
 # 解锁挖矿账户
 > personal.unlockAccount(personal.listAccounts[0])
Passphrase: // 输入创建账户时,括号里的参数,即账户的密码,"123456"
Unlock account 0x449f09d90a4726db78b86972528fc99ea00777d8

# 预估gas
> eth.estimateGas({data:publicBinCode})
199867

> var publicAbiContract=eth.contract(publicAbiCode)
undefined
> var publicContract=publicAbiContract.new({from:personal.listAccounts[0],data:publicBinCode,gas:200000})
undefined

# 开始挖矿
> miner.start()
> miner.stop()

# 查看合约
> publicContract
{
  abi: [{
      constant: true,
      inputs: [{...}, {...}],
      name: "check",
      outputs: [{...}],
      payable: false,
      stateMutability: "pure",
      type: "function"
  }],
  address: "0x291f3347f9cb6d58ca9c24b61f87bf2348b15d2f",
  transactionHash: "0xf9cbfcf8027a085106855eb31b1e10368b63bca177c2b9fffe9131d179bf061b",
  allEvents: function(),
  check: function()
}

> publicContract.address
"0x291f3347f9cb6d58ca9c24b61f87bf2348b15d2f"

3.1 常见问题

<1>错误:无法解锁挖矿账户

如果解锁账户过程中报以下错误:

account unlock with HTTP access is forbidden

因为新版本geth,出于安全考虑,默认禁止了HTTP通道解锁账户,解决办法是在启动服务端时加上参数

--allow-insecure-unlock
# 完整的启动命令
geth --networkid 123 --datadir dataChain --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --port 3000 --allow-insecure-unlock

注意事项:

  • bin赋值时需要在数字前加’0x’,然后将一串数字放入引号内(单双引号均可)
  • abi赋值时不需要加内容,也不需要加引号!

三、Java 通过web3j 调用智能合约

1. 将web3j编译生成的java合约文件拷贝到工程中

package access.contract;

import java.math.BigInteger;
import java.util.Arrays;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.tx.Contract;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.ContractGasProvider;

/**
 * 

Auto generated code. *

Do not modify! *

Please use the web3j command line tools, * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the * codegen module to update. * *

Generated with web3j version 4.3.0. */ public class CheckContract extends Contract { private static final String BINARY = "608060405234801561001057600080fd5b50610227806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063725dbc4014610046575b600080fd5b34801561005257600080fd5b506100f3600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061010d565b604051808215151515815260200191505060405180910390f35b60008151835114151561012357600090506101f5565b826040518082805190602001908083835b6020831015156101595780518252602082019150602081019050602083039250610134565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060001916836040518082805190602001908083835b6020831015156101c0578051825260208201915060208101905060208303925061019b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019161490505b929150505600a165627a7a72305820780ddfaae258de09943d9399c67ea187c86272e789ea36798919fc34edf3656b0029"; public static final String FUNC_CHECK = "check"; @Deprecated protected CheckContract(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); } protected CheckContract(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, credentials, contractGasProvider); } @Deprecated protected CheckContract(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); } protected CheckContract(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); } public RemoteCall check(String attributeA, String attributeB) { final Function function = new Function(FUNC_CHECK, Arrays.asList(new org.web3j.abi.datatypes.Utf8String(attributeA), new org.web3j.abi.datatypes.Utf8String(attributeB)), Arrays.>asList(new TypeReference() {})); return executeRemoteCallSingleValueReturn(function, Boolean.class); } @Deprecated public static CheckContract load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { return new CheckContract(contractAddress, web3j, credentials, gasPrice, gasLimit); } @Deprecated public static CheckContract load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { return new CheckContract(contractAddress, web3j, transactionManager, gasPrice, gasLimit); } public static CheckContract load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { return new CheckContract(contractAddress, web3j, credentials, contractGasProvider); } public static CheckContract load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { return new CheckContract(contractAddress, web3j, transactionManager, contractGasProvider); } public static RemoteCall deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { return deployRemoteCall(CheckContract.class, web3j, credentials, contractGasProvider, BINARY, ""); } @Deprecated public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { return deployRemoteCall(CheckContract.class, web3j, credentials, gasPrice, gasLimit, BINARY, ""); } public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { return deployRemoteCall(CheckContract.class, web3j, transactionManager, contractGasProvider, BINARY, ""); } @Deprecated public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { return deployRemoteCall(CheckContract.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, ""); } }

2. web3j 工具类连接区块链

public class Web3JClient {

    // 启动区块链服务端时的 rpcaddr 和 rpcport 参数,如果没有使用了其他参数,则需要在这里修改
    private static String url = "http://127.0.0.1:8545/";

    private Web3JClient() {
    }

    private volatile static Web3j web3j;

    public static Web3j getClient() {
        if (web3j == null) {
            synchronized (Web3JClient.class) {
                if (web3j == null) {
                    web3j = Web3j.build(new HttpService(url));
                }
            }
        }
        return web3j;
    }
}

3. 调用智能合约里的方法

public class ContractService {
    private static Web3j web3j = Web3JClient.getClient();

    /**
     * 调用合约的方法
     */
    public static Boolean publicCheck(String contractAddress, String subAttribute, String objAttribute) {
        try {
            // 获取第一个账户
            String minerBaseAccount = web3j.ethAccounts().send().getAccounts().get(0);

            Credentials credentials = Credentials.create(minerBaseAccount);

            // 合约对象
            CheckContract checkContract = CheckContract.load(contractAddress, web3j, credentials, Contract.GAS_PRICE, Contract.GAS_PRICE);
            return checkContract.check(subAttribute, objAttribute).send();
        } catch (Exception e) {
            System.out.println("exception");
            return null;
        }
    }
}

你可能感兴趣的:(区块链)