div#pop_ad { opacity: 0; }

struct Abstract { uint timestamp; address sender; uint version; bytes32 hash; byte[512] extend;}pragma solidity ^0.4.17;contract DataModel { struct Abstract { uint timestamp; address sender; uint version; bytes32 hash; byte[512] extend; } mapping(bytes32 = Abstract) abstractData; mapping(address = bool) public allowedMap; address[] public allowedArray; event AddressAllowed(address _handler, address _address); event AddressDenied(address _handler, address _address); event DataSaved(address indexed _handler, uint timestamp, address indexed sender, uint version, bytes32 hash); event ExtendSaved(address indexed _handler, byte[512] extend); event ExtendNotSave(address indexed _handler, uint version, byte[512] extend); function DataModel() public { allowedMap[msg.sender] = true; allowedArray.push(msg.sender); } modifier allow() { require(allowedMap[msg.sender] == true); _; } function allowAccess(address _address) allow public { allowedMap[_address] = true; allowedArray.push(_address); AddressAllowed(msg.sender, _address); } function denyAccess(address _address) allow public { allowedMap[_address] = false; AddressDenied(msg.sender, _address); } function getData(bytes32 _key) public view returns(uint, address, uint, bytes32, byte[512]) { return ( abstractData[_key].timestamp, abstractData[_key].sender, abstractData[_key].version, abstractData[_key].hash, abstractData[_key].extend ); } function setData(bytes32 _key, uint timestamp, address sender, uint version, bytes32 hash) allow public { abstractData[_key].timestamp = timestamp; abstractData[_key].sender = sender; abstractData[_key].version = version; abstractData[_key].hash = hash; DataSaved(msg.sender, timestamp, sender, version, hash); } function setExtend(bytes32 _key, byte[512] extend) allow public { if (abstractData[_key].version 0) { for (uint256 i; i 512; i++) { abstractData[_key].extend[i] = extend[i]; } ExtendSaved(msg.sender, extend); } else { ExtendNotSave(msg.sender, abstractData[_key].version, extend); } }}pragma solidity ^0.4.20;import "./data-model.sol";contract Storage { DataModel dataModel; uint currentVersion = 1; event StorageSaved(address handler, bytes32 indexed hashKey, uint timestamp, uint version, byte[512] extend); function Storage(address dataModelAddress) public { dataModel = DataModel(dataModelAddress); // require(dataModelAddress.delegatecall(bytes4(keccak256("allowAccess(address)")), this)); } function getData(bytes32 key) public view returns(uint timestamp, address sender, uint version, bytes32 hashKey, string extend) { byte[512] memory extendByte; (timestamp, sender, version, hashKey, extendByte) = dataModel.getData(key); bytes memory bytesArray = new bytes(512); for (uint256 i; i 512; i++) { bytesArray[i] = extendByte[i]; } extend = string(bytesArray); return(timestamp, sender, version, hashKey, extend); } function saveData(bytes32 hashKey, byte[512] extend) public { dataModel.setData(hashKey, block.timestamp, msg.sender, currentVersion, hashKey); dataModel.setExtend(hashKey, extend); StorageSaved(msg.sender, hashKey, block.timestamp, currentVersion, extend); }}import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types")// 初始化 RPC 连接RPCClient, _ := rpc.Dial(conf.BlockChainConf.RPCUrl)// 初始化 ethclientcli := ethclient.NewClient(RPCClient)// 导入 ABI 接口字符串parsedABI, _ := abi.JSON(strings.NewReader(evidenceABI))// 初始化合约实例evidence := bind.NewBoundContract(conf.BlockChainConf.ContractAddress, parsedABI, cli, cli, nil)// 初始化上下文ctx, cancel := context.WithTimeout(context.Background(), conf.BlockChainConf.ConnTimeout)defer cancel()// 交易签名私钥auth := bind.NewKeyedTransactor(account.PrivateKey)auth.Context = ctx// 调用 RPC 发送存证合约交易tx, _ := evidence.Transact(auth, "saveData", hash, stringToBytes512(extend))最终返回的 tx 则为交易信息,这时候交易并没有即时出块,需要等待出块节点出块;这里通过监听合约的日志事件来实现:// 订阅事件的过滤条件,这里传入合约的地址query := ethereum.FilterQuery{ Addresses: []common.Address{conf.BlockChainConf.ContractAddress},}// Log 通道接收var logChan = make(chan types.Log)ctx := context.Background()// 初始化客户端client, _ := blockchain.InitClient()// 初始化事件监听subscribe, _ := client.SubscribeFilterLogs(ctx, query, logChan)// 同样解析出 ABI 合约接口parsedABI, _ := abi.JSON(strings.NewReader(evidenceABI))// 收到的事件结构,和合约代码中数据结构对应var receivedData struct { Handler common.Address HashKey common.Hash Timestamp *big.Int Version *big.Int Extend Bytes512}for { select { case err := -evt.Subscribe.Err(): fmt.Printf("receive Error: %s\n", err.Error()) case log := -LogChan: // 解包收到的 Log,receivedData 则为接收事件的数据 err := parsedABI.Unpack( receivedData, "StorageSaved", log.Data) }}// 对应存证的 evidence.Transact 方法err = evidence.Call(callOpts, output, "getData", key)另一种方式是通过合约的 Log 过滤来实现,如下:// 这里过滤条件选用合约中 Map 数据的 Keyquery := ethereum.FilterQuery{ Topics: [][]common.Hash{[]common.Hash{}, []common.Hash{hashKey}},}// 调用 Client 的 FilterLogs 方法logs, err := client.FilterLogs(ctx, query)
添加新手交流群:币种分析、每日早晚盘分析
添加助理微信,一对一亲自指导:YoYo8abc