该教程旨在学习智能合约的交互方式。
智能合约的创建和发布过程请阅读上一篇博文。
一、 创建智能合约并发布到测试网络
测试合约旨在用于版权分发,具体编译部署教程参考上一篇博文,本篇不再解释。
合约代码如下:
pragma solidity ^0.4.0;
import 'zeppelin-solidity/contracts/math/SafeMath.sol';
contract CMContract {
using SafeMath for uint256;
address private creator; // the creator
mapping(address => uint256) balances; // token
mapping(string => bool) copyrights_keys; // keys for copyrights
mapping(string => CopyRight) copyrights; // copyrights {id_in_server : CopyRight}
address private zero_address = 0x0000000000000000000000000000000000000000;
// copy right
struct CopyRight {
string ipfs_address; //ipfs hash address
string id_in_server; // id of this IP in internal server database
string cp_hash; //
mapping(address => bool) owners_keys;
address[] owners_addresses;
mapping(address => uint256) owners_integer;
mapping(address => uint256) owners_decimals;
}
// init
function CMContract() public {
creator = msg.sender;
}
// update a copyright
function update_copyright(string ipfs_address, string id_in_server,string cp_hash, address owner, uint256 share_integer, uint256 share_decimals) public returns (bool) {
CopyRight storage cp = copyrights[id_in_server];
cp.ipfs_address = ipfs_address;
cp.id_in_server = id_in_server;
cp.cp_hash = cp_hash;
if (copyrights_keys[id_in_server] == false) {
// new ip
cp.owners_keys[owner] = true;
cp.owners_addresses.push(owner);
cp.owners_integer[owner] = share_integer;
cp.owners_decimals[owner] = share_decimals;
copyrights_keys[id_in_server] = true;
} else {
// if owner exits
if (cp.owners_keys[owner] == true) {
// update share
cp.owners_integer[owner] = share_integer;
cp.owners_decimals[owner] = share_decimals;
if (share_integer == 0 && share_decimals == 0) {
cp.owners_keys[owner] = false;
}
} else {
// push a new owner
cp.owners_keys[owner] = true;
cp.owners_addresses.push(owner);
cp.owners_integer[owner] = share_integer;
cp.owners_decimals[owner] = share_decimals;
}
}
return true;
}
// delete a copyright
function delete_copyright(string id_in_server) public returns (bool){
if (copyrights_keys[id_in_server] == true) {
copyrights_keys[id_in_server] = false;
}
return true;
}
// id_in_server : id of this IP in internal server database
function get_copyright_share(string id_in_server, address owner) public view returns (uint256, uint256, bool) {
if (copyrights_keys[id_in_server] == true) {
CopyRight storage cp = copyrights[id_in_server];
if (cp.owners_keys[owner] == true) {
return (cp.owners_integer[owner], cp.owners_decimals[owner],true);
} else {
return (0,0,true);
}
} else {
return (0,0,false);
}
}
// get balance
function balance_of(address _user) public view returns (uint256 balance) {
return balances[_user];
}
// transfer token from a to b
function transfer(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
// SafeMath.sub will throw if there is not enough balance.
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
return true;
}
// *** only creator can use the functions below ***
// generate token for users
function generate_token (address _to, uint256 _value) public returns (bool) {
require(msg.sender == creator);
balances[_to] = balances[_to].add(_value);
return true;
}
// *** tools ***
// string a equal to string b ?
function string_equal_to(string _a, string _b) private pure returns (bool) {
if (keccak256(_a) == keccak256(_b)) {
return true;
}
return false;
}
}
编译部署后得到一个build文件夹
二、通过Web3.py与智能合约就行交互
以太坊客户端通过RPC方式调用,web3.py封装了调用的相关接口
安装web3.py包
新建一个py项目
回到第一步的build/contracts文件夹中,将CMContract.json中的"abi"和"address"的key和value拷贝下来。
在py项目中组合成一个简单的json对象
注意将abi中的false和true全部替换成python能识别的False和True
获取合约对象的条件就是abi和合约发布的address
现在通过web3.py提供的方法就可以获得智能合约对象了
from web3 import Web3, HTTPProvider
from web3.contract import ConciseContract
config = {
"abi": [...],
"address": "0x3855e692db75e5cd1e1e5e947a9dc6039ecbc0a6",
}
web3 = Web3(HTTPProvider('http://localhost:8545'))
owner = web3.eth.accounts[0]
contract_instance = web3.eth.contract(address=config['address'], abi=config['abi'],ContractFactoryClass=ConciseContract)
将智能合约的方法简单封装一下
def update_copyright(ipfs_address,id_in_server,cp_hash,owner,share_integer,share_decimals):
transact_hash = contract_instance.update_copyright(ipfs_address,id_in_server,cp_hash,owner,share_integer,share_decimals,transact={'from': owner})
return transact_hash
def delete_copyright(id_in_server):
transact_hash = contract_instance.delete_copyright(id_in_server,transact={'from': owner})
return transact_hash
def get_copyright_share(id_in_server,owner):
transact_hash = contract_instance.get_copyright_share(id_in_server, owner, transact={'from': owner})
return transact_hash
def balance_of(user):
return contract_instance.balance_of(user)
def transfer(_from, _to, _value):
transact_hash = contract_instance.transfer(_from, _to, _value, transact={'from': owner})
return transact_hash
def generate_token(_to, _value):
transact_hash = contract_instance.generate_token(_to, _value, transact={'from': owner})
return transact_hash
调用一下合约试试
if __name__ == "__main__":
generate_token(owner, 100000)
print(balance_of(owner))
给owner 也就是第一个账户生成了十万代币,获取owner的代币余额应该打印出10万
同时,在ganache-cli中也生成了新的block,用于记录该交易