下面的代码只返回一个收据,但我希望它返回一个数据元组,就像下面的契约(Contract)一样。我如何让它返回数据?我找不到关于如何保存和检索数据的好教程。我知道这是一个昂贵的用例,我只是在尝试做一个基本的概念证明并同时学习。
我正在使用 web3@1.0.0-beta.29
export class AppComponent {
title = 'app';
dappUrl: string = 'http://myapp.com';
web3: any;
contractHash: string = '0x3b8a60616bde6f6d251e807695900f31ab12ce1a';
MyContract: any;
contract: any;
ABI: any = [{"constant":true,"inputs":[{"name":"idx","type":"uint256"}],"name":"getLocationHistory","outputs":[{"name":"delegate","type":"address"},{"name":"longitude","type":"uint128"},{"name":"latitude","type":"uint128"},{"name":"name","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"recentLocation","outputs":[{"name":"delegate","type":"address"},{"name":"longitude","type":"uint128"},{"name":"latitude","type":"uint128"},{"name":"name","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"longitude","type":"uint128"},{"name":"latitude","type":"uint128"},{"name":"name","type":"bytes32"}],"name":"saveLocation","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getLastLocation","outputs":[{"components":[{"name":"delegate","type":"address"},{"name":"longitude","type":"uint128"},{"name":"latitude","type":"uint128"},{"name":"name","type":"bytes32"}],"name":"recentLocation","type":"tuple"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"locations","outputs":[{"name":"delegate","type":"address"},{"name":"longitude","type":"uint128"},{"name":"latitude","type":"uint128"},{"name":"name","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"item","outputs":[{"name":"id","type":"bytes32"},{"name":"name","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"id","type":"bytes32"},{"name":"name","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}];
constructor(private route: ActivatedRoute) { }
@HostListener('window:load')
windowLoaded() {
this.checkAndInstantiateWeb3();
this.getLocation();
}
getLocationHistory() {
this.MyContract.methods
.getLocationHistory(0).send({
'from': '0x902D578B7E7866FaE71b3AB0354C9606631bCe03',
'gas': '44000'
}).then((result) => {
this.MyContract.methods.getLocationHistory(0).call()
.then(hello => {console.log('hello', hello)});
});
}
private checkAndInstantiateWeb3 = () => {
if (typeof window.web3 !== 'undefined') {
console.warn('Using web3 detected from external source.');
// Use Mist/MetaMask's provider
this.web3 = new Web3(window.web3.currentProvider);
} else {
console.warn(`No web3 detected. Falling back to http://localhost:8545.`);
this.web3 = new Web3(
new Web3.providers.HttpProvider('http://localhost:8545')
);
}
this.MyContract = new this.web3.eth.Contract(this.ABI, this.contractHash);
}
private getLocation(): void {
let query = this.route.snapshot.queryParams;
if (query.action && query.action === 'setLocation') {
this.setLocation();
}
}
private setLocation(): void {
navigator.geolocation.getCurrentPosition((position) => {
this.MyContract.methods.saveLocation(
position.coords.longitude, position.coords.latitude, window.web3.fromAscii("test")
).send({'from': '0x902D578B7E7866FaE71b3AB0354C9606631bCe03'}
).then((result) => {
console.log('saveLocation')
console.log(result)
});
this.getLocationHistory();
});
}
}
Solidity 合约
pragma solidity ^0.4.11;
/// @title QRCodeTracking with delegation.
contract QRCodeTracking {
struct Location {
address delegate;
uint128 longitude;
uint128 latitude;
bytes32 name;
}
struct Item {
bytes32 id;
bytes32 name;
}
Item public item;
Location[] public locations;
Location public recentLocation;
function QRCodeTracking(bytes32 id, bytes32 name) public {
// Limit gas
locations.length = 100;
item = Item({id: id, name: name});
}
function saveLocation (
uint128 longitude,
uint128 latitude,
bytes32 name
) public constant {
locations.push(Location({
delegate: msg.sender,
longitude: longitude,
latitude: latitude,
name: name
}));
}
function getLocationHistory(uint idx) constant
returns (address delegate, uint128 longitude, uint128 latitude, bytes32 name) {
Location storage loc = locations[idx];
return (loc.delegate, loc.longitude, loc.latitude, loc.name);
}
function getLastLocation() public
returns (Location recentLocation) {
recentLocation = locations[locations.length - 1];
return recentLocation;
}
}
最佳答案
您的代码存在一些问题,主要围绕 constant
函数的使用以及了解 web3 中 send
和 call
之间的区别。
在 Solidity 中, constant
(或 view
)修饰符用于标记不改变状态的合约函数(参见 docs )。如果您尝试在 constant
函数中更新合约状态,则状态更改将不会持续。因此,在您的 Solidity 合约中, saveLocation
不应该是 constant
。但是, getLastLocation
和 getLocationHistory
都只从 state 中读取,所以它们都应该是 constant
。
在客户端,使用 web3 调用合约函数时也有同样的区别。当您想在区块链上执行交易时使用 send
,但当您想从合约中检索数据时使用 call
。
当您使用 this.MyContract.methods.getLocationHistory(0).send()
时,您正在针对您的合约执行交易,并且交易收据通过传入的回调(或通过 .then
Promise)发送回来。可以在 here 中找到用于发送的 Web3 文档。重要说明 - 执行交易的 Solidity 函数无法返回合约状态中的任何内容。如果在非常量函数中有 returns
,它会编译,但不会返回数据。从合约返回数据的唯一方法是使用 constant
函数或使用 events 。对于您的用例,您想使用 this.MyContract.methods.getLocationHistory(0).call()
。 Call web3 documentation.
编辑 - 添加简化的测试客户端。注意 send
与 call
的使用。
const Web3 = require('web3');
const solc = require('solc');
const fs = require('fs');
const provider = new Web3.providers.HttpProvider("http://localhost:8545")
const web3 = new Web3(provider);
web3.eth.getAccounts().then((accounts) => {
const code = fs.readFileSync('./QRCodeTracking.sol').toString();
const compiledCode = solc.compile(code);
const byteCode = compiledCode.contracts[':QRCodeTracking'].bytecode;
// console.log('byteCode', byteCode);
const abiDefinition = JSON.parse(compiledCode.contracts[':QRCodeTracking'].interface);
const deployTransactionObject = {
data: byteCode,
from: accounts[0],
gas: 4700000
};
let deployedContract;
const MyContract = new web3.eth.Contract(abiDefinition, deployTransactionObject);
MyContract.deploy({arguments: [web3.utils.asciiToHex("someId"), web3.utils.asciiToHex("someName")]}).send((err, hash) => {
if (err)
console.log("Error: " + err);
else
console.log("TX Hash: " + hash);
}).then(result => {
deployedContract = result;
deployedContract.setProvider(provider);
return deployedContract.methods.saveLocation(123456789, 987654321, web3.utils.asciiToHex("newLocationName")).send();
}).then(saveResult => {
return deployedContract.methods.getLocationHistory(0).call();
}).then(locationResult => {
console.log(locationResult);
})
});
关于blockchain - 如何使用 Solidity 和 Web.js 在以太坊区 block 链上保存和检索数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48603051/