Cypherium Java smart contract programming guide

转载请标注原文地址:https://blog.csdn.net/lilyssh/article/details/82911309

代币就是数字货币,比特币、以太币就是一个代币。利用Cypherium的java智能合约可以轻松编写出属于自己的代币。这些代币是建立在区块链之上,代表你拥有并可转让给其他人的数字资产。现在我们就来看看怎样创建一个这样的代币。

准备工作:

  1. 下载示例代码。https://github.com/cypherium/ContractExample
    目录结构介绍:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    ├── client              //客户端
    │   ├── cypher //可执行文件cypher
    │   ├── jdk //Java Development Kit
    │   ├── genesis.json //初始化创世区块所需文件
    │   ├── db //自定义数据库目录
    │   └── executable_file //可执行文件
    │   ├── Linux //Linux版本
    │   │ └── cypher
    │   ├── Mac //Mac版本
    │   │ └── cypher
    │   └── Windows //Windows版本
    │   └── cypher
    ├── file2str //class文件生成二进制字符串工具
    │   ├── file2str.go //go源码
    │   ├── Linux //Linux版本
    │   │   └── file2str
    │   ├── Mac //Mac版本
    │   │ └── file2str
    │   └── Windows //Windows版本
    │      └── file2str.exe
    └── src
    ├── HelloWorld.java //Java智能合约
    ├── index.html //合约部署页面
    └── web3.js

接下来的操作步骤,默认在ContractExample/client目录执行。
请根据操作系统,把合适的可执行文件cypher,复制到client下,如:

1
cp executable_file/Mac/cypher ./

  1. 初始化节点的创世区块。datadir为自行指定的数据库目录,如db。
1
./cypher --datadir db init genesis.json
  1. 启动节点。
1
./build/bin/cypher --datadir db --networkid 123666 --port 7000 --rpcport 8000  --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0
  1. 启动节点的js交互窗口(用上一步成的ipc文件):
1
./cypher attach db/cypher.ipc
  1. 创建账户。
1
personal.newAccount("your password")
  1. 请联系我们,给您的测试账户中,转入一些可供测试的代币。邮箱地址:xxx
  2. 查看您的账户余额。
1
cph.getBalance("your account address")
  1. 您可以通过以下方法,把您账户中的资金转给其他账户。
1
cph.sendTransaction(from,to,value,gas,gasPrice,data,nonce,Function)
  • from: String - 指定的发送者的地址。
  • to: String - (可选)交易消息的目标地址,如果是合约创建,则不填。
  • value: Number|String|BigNumber - (可选)交易携带的货币量,以wei为单位。如果合约创建交易,则为初始的基金。
  • gas: Number|String|BigNumber - (可选)默认是自动,交易可使用的gas,未使用的gas会退回。
  • gasPrice: Number|String|BigNumber - (可选)默认是自动确定,交易的gas价格,默认是网络gas价格的平均值 。
  • data: String - (可选)或者包含相关数据的字节字符串,如果是合约创建,则是初始化要用到的代码。
  • nonce: Number - (可选)整数,使用此值,可以允许你覆盖你自己的相同nonce的,正在pending中的交易。
  • Function - 回调函数,用于支持异步的方式执行。
  1. 通过以下命令查看现在共识到第几个区块了。
1
cph.txBlockNumber

API

ERC20是以太坊定义的一个代币标准。要求我们在实现代币的时候必须要遵守的协议,如指定代币名称、总量、实现代币交易函数等,只有支持了协议才能被以太坊钱包支持。
Cypherium的代币标准接口如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package javax.cypher;

public final class Cypnet {
/**
* 设置代币信息。
* @param symbol 代币符号
* @param name 代币名称
* @param totalSupply 发行代币总量
* @param _owner 合约拥有者账户地址,传""空时,代表默认为创建者账户地址
* @return
*/
public static native boolean setTokenInfo(String symbol, String name, long totalSupply, String _owner);

/**
* 获取合约创建者的账户地址。
* @param addressType can be "caller","self","owner" and other filter
* @return
*/
public static native String getAddress(String addressType);

/**
* 查看对应账号的代币余额。
* @param _address
* @return
*/
public static native long balanceOf(String _address);

/**
* 修改指定账户余额。
* @param _from
* @param _value
* @return
*/
public static native boolean changeBalance(String _from, long _value);

/**
* 实现代币交易
* @param _from
* @param _to
* @param _value
* @return
*/
public static native boolean transfer(String _from, String _to, long _value);

/**
* 设置键值对。
* @param _key
* @param _value
* @return
*/
public static native boolean setState(String _key, String _value);

/**
* 通过键获取值。
* @param _key
* @return
*/
public static native String getState(String _key);

static {
}
}

Create contract

现在我们来开始编写第一个Java智能合约,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import javax.cypher.Cypnet;

public class HelloWorld {
public static void main(String[] args) {
long totalSupply = 10000;
//我们创建一个 符号为Hello,名称为Hello world,发行总量为10000的代币。
Cypnet.setTokenInfo("Hello", "Hello world", totalSupply, "");
//把发行的代币全都给合约创建者
Cypnet.changeBalance("caller", totalSupply);
System.out.println("Hello");
}

public static String transfer(String _to, long _value) {
long n = Cypnet.balanceOf("caller");
if (n < _value) {
//throw new Exception("Insufficient balance");
return "Insufficient balance";
}
Cypnet.transfer("caller", _to, _value);
return null;
}

public static String getValue(String skey) {
String s = Cypnet.getState(skey);
return s;
}

public static String setValue(String skey, String sValue) {
Cypnet.setState(skey, sValue);
return "ok";
}
}

简单解释下,我们定义了一个名为HelloWorld的合约,main方法是Java应用程序的入口方法,导入Cypnet类。

Compile contract

  1. 我们来把HelloWorld.java编译成字节码文件HelloWorld.class。编译命令如下:
1
javac -cp jdk/classes ../src/HelloWorld.java
  1. file2str赋上权限。
1
chmod -R 777 ../file2str

3.根据操作系统,选择合适的file2str,将 HelloWorld.class文件转成16进制字符串的命令 file2str HelloWorld.class,如Mac版为:

1
../file2str/Mac/file2str ../src/HelloWorld.class

会看到生成的二进制字符串:

1
0xcafebabe00000036005a0a001a002d05000000000000271008002e08002f0800300a003100320800330a003100340800350800360a00310037090038003908003a0a003b003c0a0031003d0a0031003e08003f0a003100400800410800420a003b00430800440800450700460700470100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100046d61696e010016285b4c6a6176612f6c616e672f537472696e673b29560100087472616e73666572010027284c6a6176612f6c616e672f537472696e673b4a294c6a6176612f6c616e672f537472696e673b01000d537461636b4d61705461626c6501000867657456616c7565010026284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b01000873657456616c7565010038284c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f537472696e673b01000967657456616c75653101001428294c6a6176612f6c616e672f537472696e673b01000967657456616c75653201000a536f7572636546696c6501000f48656c6c6f576f726c642e6a6176610c001b001c01000548656c6c6f01000b48656c6c6f20776f726c640100000700480c0049004a01000663616c6c65720c004b004c0100047465737401001048656c6c6f20776f726c6420746573740c004d004e07004f0c0050005101001448656c6c6f20776f726c6420436f6e74726163740700520c005300540c005500250c00560057010014496e73756666696369656e742062616c616e63650c00210058010004414141410100026f6b0c0053005901000973647364736473646401000331303001000a48656c6c6f576f726c640100106a6176612f6c616e672f4f626a6563740100136a617661782f6379706865722f4379706e657401000c736574546f6b656e496e666f01003a284c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b4a4c6a6176612f6c616e672f537472696e673b295a01000d6368616e676542616c616e6365010016284c6a6176612f6c616e672f537472696e673b4a295a0100087365745374617465010027284c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b295a0100106a6176612f6c616e672f53797374656d0100036f75740100154c6a6176612f696f2f5072696e7453747265616d3b0100136a6176612f696f2f5072696e7453747265616d0100077072696e746c6e010015284c6a6176612f6c616e672f537472696e673b2956010008676574537461746501000962616c616e63654f66010015284c6a6176612f6c616e672f537472696e673b294a010028284c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b4a295a0100042849295600210019001a0000000000070001001b001c0001001d0000001d00010001000000052ab70001b100000001001e000000060001000000030009001f00200001001d00000068000500040000003414000240120412051f1206b800075712081fb8000957120a120bb8000c57b2000d120eb6000f120ab800104eb2000d2db6000fb100000001001e0000002200080000000500040008000f00090016000b001e000c0026000e002c000f003300100009002100220001001d0000007a00040006000000351208b80011370416041f949c00061212b012082a1fb8001357120ab800104eb2000d2db6000f1214b800104eb2000d2db6000f01b000000002001e0000002600090000001400070015000e0017001100190019001b001f001c0026001e002c001f003300210023000000070001fd001100040009002400250001001d0000002300010002000000072ab800104c2bb000000001001e0000000a000200000025000500260009002600270001001d0000002500020002000000092a2bb8000c571215b000000001001e0000000a0002000000290006002a0009002800290001001d0000004e0002000100000019033b1a112710a20010b2000d1ab60016840001a7ffef1217b000000002001e0000001600050000003e000200400009004100100042001600440023000000070002fc000201130009002a00290001001d0000001b00010000000000031218b000000001001e000000060001000000470001002b00000002002c

  1. 部署合约
    我们需要用Chrome浏览器打开部署调用页面ContractExample/src/index.html
    如下:

如果使用的是其他浏览器,直接打开会有跨域请求问题,所以需要使用http-server来部署该页面,需要自行先安装node和npm,再安装http-server,请依次执行以下命令:

1
2
3
4
5
npm install http-server -g 

pm i http-server

yarn -g http-server

进入到CypherTestNet/web3-cypher.js目录下,执行

1
http-server

用浏览器访问http://127.0.0.1:8080 把刚生成的二进制字符串粘到Java contract bytecode文本框。
在From Account账户有余额的情况下,点击Deploy按钮后,会把您的java合约部署到区块链中。并会弹出合约地址信息。



点击Get contract info按钮获取区块链中的合约信息。

在文本框中输入转账金额,并点击Transfer按钮,付款方就会向收款方转账。

点击From’s Balance按钮查看付款账户的余额。

点击To’s Balance按钮查看收款账户的余额。

View deploy contract page

接下来,我们来看看部署调用页面的流程。

  1. web3如何调用java方法
    ABI全称Application Binary Interface, 是调用智能合约函数以及合约之间函数调用的消息编码格式定义,也可以理解为智能合约函数调用的接口说明. 类似Webservice里的SOAP协议一样;也就是定义操作函数签名,参数编码,返回结果编码等。使用ABI协议时必须要求在编译时知道类型,即强类型相关.

如果想调用HelloWorld.java中的函数,需要把该函数追加到abi变量中,按照现有格式即可。比如说,我们想要调用HelloWorld.java中的getValue方法,就要把以下内容追加到abi变量中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var abi=
...
,
{
"constant":false, //方法修饰符,false表示函数内可以修改状态变量
"inputs":[ //方法入参,数组里的每个对象都是一个参数说明
{
"name":"skey", //第一个参数的名字
"type":"bytes32" //第一个参数的类型
}
],
"outputs":[ //方法返回值,数组里的每个对象都是一个参数说明
{
"name":"value", //第一个参数的名字
"type":"bytes32" //第一个参数的类型
}
],
"name":"getValue", //方法名
"payable":false,
"stateMutability":"nonpayable",
"type":"function" //方法类型:function,constructor,fallback,event
}
]

uint:M为integer类型代表M bits,0 < M <= 256, M % 8 == 0,如uint32,uint8,uint256。
int:同上。同为从8到256位的无符号整数。
uint和int:整型,分别是uint256和int256的别名。这也是上面的例子中函数参数类型是uint,转sha3码时要变成uint256的原因。
address:地址,20个字节,160bits,一个Ethereum地址,地址的类型也可以有成员作为所有合约的base。
bool:布尔类型,1个字节,true:1,false:0。
bytes:固定大小的字节数组,0<M<=32,byte都是bytes1的别名。
bytes:动态分配大小字节数组。不是一个值类型。
String:动态大小UTF8编码的字符串,不是一个值类型。
尽量少用string。

  1. 如何发布合约
    web3.js对合约的操作进行了封装。发布合约时,可以使用web3.cph.contract的new方法。
    部署过程中需要主要的是,new方法的回调会执行两次,第一次是合约的交易创建完成,第二次是在某个地址上完成部署。需要注意的是只有在部署完成后,才能进行方法该用,否则会报错TypeError: javaContract.add is not a function。
本文由 lilyssh创作。可自由转载、引用,但需署名作者且注明文章出处。


当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器