Teraz, gdy mamy naszą inteligentną umowę i jej szczegóły, przygotujemy obiekt umowy web3 ze szczegółami tej umowy, a następnie wdrożymy tę umowę do łańcucha bloków Ethereum, wywołując metodę wdrażania na obiekcie umowy. Musimy stworzyć obiekt klasy web3.eth.Contract, który może reprezentować naszą umowę. Poniższy fragment kodu tworzy instancję kontraktu z ABI naszej umowy jako dane wejściowe do konstruktora.
var pollingContract = new web3.eth.Contract([
{
“constant”: true,
“inputs”: [
{
“name”: “”,
“type”: “address”
}
],
“name”: “votes”,
“outputs”: [
{
“name”: “”,
“type”: “uint256”
}
],
“payable”: false,
“stateMutability”: “view”,
“type”: “function”
},
{
“constant”: true,
“inputs”: [],
“name”: “getPoll”,
“outputs”: [
{
“name”: “”,
“type”: “string”
}
],
“payable”: false,
“stateMutability”: “view”,
“type”: “function”
},
{
“anonymous”: false,
“inputs”: [
{
“indexed”: false,
“name”: “_voter”,
“type”: “address”
},
{
“indexed”: false,
“name”: “_value”,
“type”: “uint256”
}
],
“name”: “Voted”,
“type”: “event”
},
{
“constant”: false,
“inputs”: [
{
“name”: “selection”,
“type”: “uint256”
}
],
“name”: “vote”,
“outputs”: [],
“payable”: false,
“stateMutability”: “nonpayable”,
“type”: “function”
}
]);
Teraz musimy wdrożyć tę umowę w sieci Ethereum przy użyciu metody wdrażania biblioteki web3. Poniższy fragment kodu pokazuje, jak to zrobić. W tym fragmencie dodaliśmy kod bajtu w polu danych obiektu przekazanego do metody wdrażania.
pollingContract
.deploy({
data: ‘0x606060405260806040519081016040528060508152602
0017f53686f756c6420636f66666565206265206d6164652074617
820667265653f2081526020017f53656e64203120666f722079657
3204f52203220666f72206e6f20696e20746881526020017f65207
66f74652066756e6374696f6e2e000000000000000000000000000
000008152506001908051906020019061009c9291906100ad565b5
034156100a857600080fd5b610152565b828054600181600116156
101000203166002900490600052602060002090601f01602090048
1019282601f106100ee57805160ff191683800117855561011c565
b8280016001018555821561011c579182015b8281111561011b578
251825591602001919060010190610100565b5b509050610129919
061012d565b5090565b61014f91905b8082111561014b576000816
000905550600101610133565b5090565b90565b610373806101616
000396000f300606060405260043610610057576000357c0100000
000000000000000000000000000000000000000000000000000900
463ffffffff1680630121b93f1461005c57806303c322781461007
f578063d8bff5a51461010d575b600080fd5b34156100675760008
0fd5b61007d600480803590602001909190505061015a565b005b3
41561008a57600080fd5b610092610273565b60405180806020018
281038252838181518152602001915080519060200190808383600
05b838110156100d25780820151818401526020810190506100b75
65b50505050905090810190601f1680156100ff578082038051600
1836020036101000a031916815260200191505b509250505060405
180910390f35b341561011857600080fd5b610144600480803573f
fffffffffffffffffffffffffffffffffffffff169060200190919
0505061031b565b604051808281526020019150506040518091039
0f35b7f4d99b957a2bc29a30ebd96a7be8e68fe50a3c701db28a91
436490b7d53870ca43382604051808373fffffffffffffffffffff
fffffffffffffffffff1673fffffffffffffffffffffffffffffff
fffffffff168152602001828152602001925050506040518091039
0a160008060003373fffffffffffffffffffffffffffffffffffff
fff1673ffffffffffffffffffffffffffffffffffffffff1681526
020019081526020016000205414151561021257600080fd5b60008
11180156102225750600381105b151561022d57600080fd5b80600
0803373ffffffffffffffffffffffffffffffffffffffff1673fff
fffffffffffffffffffffffffffffffffffff16815260200190815
26020016000208190555050565b61027b610333565b60018054600
181600116156101000203166002900480601f01602080910402602
001604051908101604052809291908181526020018280546001816
00116156101000203166002900480156103115780601f106102e65
7610100808354040283529160200191610311565b8201919060005
26020600020905b8154815290600101906020018083116102f4578
29003601f168201915b5050505050905090565b600060205280600
05260406000206000915090505481565b602060405190810160405
2806000815250905600a165627a7a72305820ec7d3e1dae8412ec8
5045a8eafc248e37ae506802cc008ead300df1ac81aab490029′
})
.send({
from: ‘0xbaf735f889d603f0ec6b1030c91d9033e60525c3’,
gas: 4700000,
gasPrice: ‘20000000000000’
},
function(error, transactionHash){
console.log(error);
console.log(transactionHash);
})
.then(function(contract){
console.log(contract);
});
Pamiętaj, że korzystaliśmy również z konta utworzonego podczas konfiguracji sieci w polu „z” funkcji wysyłania. Ponieważ to konto zostało wstępnie zasilone dziewięcioma Ether i jest również dodane jako konto eterowe dla nagród górniczych, ma wystarczającą ilość Etheru do wdrożenia kontraktu. Pełna funkcja do wdrożenia umowy będzie
var deployContract = function () {
var pollingContract = new web3.eth.Contract([{
“constant”: true,
“inputs”: [{
“name”: “”,
“type”: “address”
}],
“name”: “votes”,
“outputs”: [{
“name”: “”,
“type”: “uint256”
}],
“payable”: false,
“stateMutability”: “view”,
“type”: “function”
},
{
“constant”: true,
“inputs”: [],
“name”: “getPoll”,
“outputs”: [{
“name”: “”,
“type”: “string”
}],
“payable”: false,
“stateMutability”: “view”,
“type”: “function”
},
{
“anonymous”: false,
“inputs”: [{
“indexed”: false,
“name”: “_voter”,
“type”: “address”
},
{
“indexed”: false,
“name”: “_value”,
“type”: “uint256”
}
],
“name”: “Voted”,
“type”: “event”
},
{
“constant”: false,
“inputs”: [{
“name”: “selection”,
“type”: “uint256”
}],
“name”: “vote”,
“outputs”: [],
“payable”: false,
“stateMutability”: “nonpayable”,
“type”: “function”
}
]);
pollingContract
.deploy({
data: ‘0x60606040526080604051908101604052806050815
26020017f53686f756c6420636f66666565206265206d61646
52074617820667265653f2081526020017f53656e642031206
66f7220796573204f52203220666f72206e6f20696e2074688
1526020017f6520766f74652066756e6374696f6e2e0000000
00000000000000000000000008152506001908051906020019
061009c9291906100ad565b5034156100a857600080fd5b610
152565b8280546001816001161561010002031660029004906
00052602060002090601f016020900481019282601f106100e
e57805160ff191683800117855561011c565b8280016001018
555821561011c579182015b8281111561011b5782518255916
02001919060010190610100565b5b509050610129919061012
d565b5090565b61014f91905b8082111561014b57600081600
0905550600101610133565b5090565b90565b6103738061016
16000396000f300606060405260043610610057576000357c0
10000000000000000000000000000000000000000000000000
0000000900463ffffffff1680630121b93f1461005c5780630
3c322781461007f578063d8bff5a51461010d575b600080fd5
b341561006757600080fd5b61007d600480803590602001909
190505061015a565b005b341561008a57600080fd5b6100926
10273565b60405180806020018281038252838181518152602
00191508051906020019080838360005b838110156100d2578
0820151818401526020810190506100b7565b5050505090509
0810190601f1680156100ff578082038051600183602003610
1000a031916815260200191505b50925050506040518091039
0f35b341561011857600080fd5b610144600480803573fffff
fffffffffffffffffffffffffffffffffff169060200190919
0505061031b565b60405180828152602001915050604051809
10390f35b7f4d99b957a2bc29a30ebd96a7be8e68fe50a3c70
1db28a91436490b7d53870ca43382604051808373fffffffff
fffffffffffffffffffffffffffffff1673fffffffffffffff
fffffffffffffffffffffffff1681526020018281526020019
250505060405180910390a160008060003373fffffffffffff
fffffffffffffffffffffffffff1673fffffffffffffffffff
fffffffffffffffffffff16815260200190815260200160002
05414151561021257600080fd5b60008111801561022257506
00381105b151561022d57600080fd5b806000803373fffffff
fffffffffffffffffffffffffffffffff1673fffffffffffff
fffffffffffffffffffffffffff16815260200190815260200
16000208190555050565b61027b610333565b6001805460018
1600116156101000203166002900480601f016020809104026
02001604051908101604052809291908181526020018280546
00181600116156101000203166002900480156103115780601
f106102e657610100808354040283529160200191610311565
b820191906000526020600020905b815481529060010190602
0018083116102f457829003601f168201915b5050505050905
090565b6000602052806000526040600020600091509050548
1565b6020604051908101604052806000815250905600a1656
27a7a72305820ec7d3e1dae8412ec85045a8eafc248e37ae50
6802cc008ead300df1ac81aab490029′
})
.send({
from: ‘0xbaf735f889d603f0ec6b1030c91d9033e6
0525c3′,
gas: 4700000,
gasPrice: ‘20000000000000’
},
function (error, transactionHash) {
console.log(error);
console.log(transactionHash);
})
.then(function (contract) {
console.log(contract);
});
};
Po uruchomieniu tej funkcji z naszej aplikacji node.js otrzymaliśmy następujące dane wyjściowe:
Contract {
currentProvider: [Getter/Setter],
_requestManager:
RequestManager {
provider: null,
providers:
{ WebsocketProvider: [Function: WebsocketProvider],
HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider] },
subscriptions: {} },
givenProvider: null,
providers:
{ WebsocketProvider: [Function: WebsocketProvider],
HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider] },
_provider: null,
setProvider: [Function],
BatchRequest: [Function: bound Batch],
extend:
{ [Function: ex]
formatters:
{ inputDefaultBlockNumberFormatter: [Function:
inputDefaultBlockNumberFormatter],
inputBlockNumberFormatter: [Function:
inputBlockNumberFormatter],
inputCallFormatter: [Function: inputCallFormatter],
inputTransactionFormatter: [Function:
inputTransactionFormatter],
inputAddressFormatter: [Function:
inputAddressFormatter],
inputPostFormatter: [Function: inputPostFormatter],
inputLogFormatter: [Function: inputLogFormatter],
inputSignFormatter: [Function: inputSignFormatter],
outputBigNumberFormatter: [Function:
outputBigNumberFormatter],
outputTransactionFormatter: [Function:
outputTransactionFormatter],
outputTransactionReceiptFormatter: [Function:
outputTransactionReceiptFormatter],
outputBlockFormatter: [Function: outputBlockFormatter],
outputLogFormatter: [Function: outputLogFormatter],
outputPostFormatter: [Function: outputPostFormatter],
outputSyncingFormatter: [Function:
outputSyncingFormatter] },
utils:
{ _fireError: [Function: _fireError],
_jsonInterfaceMethodToString: [Function:
_jsonInterfaceMethodToString],
randomHex: [Function: randomHex],
_: [Function],
BN: [Function],
isBN: [Function: isBN],
isBigNumber: [Function: isBigNumber],
isHex: [Function: isHex],
isHexStrict: [Function: isHexStrict],
sha3: [Function],
keccak256: [Function],
soliditySha3: [Function: soliditySha3],
isAddress: [Function: isAddress],
checkAddressChecksum: [Function: checkAddressChecksum],
toChecksumAddress: [Function: toChecksumAddress],
toHex: [Function: toHex],
toBN: [Function: toBN],
bytesToHex: [Function: bytesToHex],
hexToBytes: [Function: hexToBytes],
hexToNumberString: [Function: hexToNumberString],
hexToNumber: [Function: hexToNumber],
toDecimal: [Function: hexToNumber],
numberToHex: [Function: numberToHex],
fromDecimal: [Function: numberToHex],
hexToUtf8: [Function: hexToUtf8],
hexToString: [Function: hexToUtf8],
toUtf8: [Function: hexToUtf8],
utf8ToHex: [Function: utf8ToHex],
stringToHex: [Function: utf8ToHex],
fromUtf8: [Function: utf8ToHex],
hexToAscii: [Function: hexToAscii],
toAscii: [Function: hexToAscii],
asciiToHex: [Function: asciiToHex],
fromAscii: [Function: asciiToHex],
unitMap: [Object],
toWei: [Function: toWei],
fromWei: [Function: fromWei],
padLeft: [Function: leftPad],
leftPad: [Function: leftPad],
padRight: [Function: rightPad],
rightPad: [Function: rightPad],
toTwosComplement: [Function: toTwosComplement] },
Method: [Function: Method] },
clearSubscriptions: [Function],
options:
{ address: [Getter/Setter],
jsonInterface: [Getter/Setter],
data: undefined,
from: undefined,
gasPrice: undefined,
gas: undefined },
defaultAccount: [Getter/Setter],
defaultBlock: [Getter/Setter],
methods:
{ votes: [Function: bound _createTxObject],
‘0xd8bff5a5’: [Function: bound _createTxObject],
‘votes(address)’: [Function: bound _createTxObject],
getPoll: [Function: bound _createTxObject],
‘0x03c32278’: [Function: bound _createTxObject],
‘getPoll()’: [Function: bound _createTxObject],
vote: [Function: bound _createTxObject],
‘0x0121b93f’: [Function: bound _createTxObject],
‘vote(uint256)’: [Function: bound _createTxObject] },
events:
{ Voted: [Function: bound ],
‘0x4d99b957a2bc29a30ebd96a7be8e68fe50a3c701db28a91436
490b7d53870ca4′: [Function: bound ],
‘Voted(address,uint256)’: [Function: bound ],
allEvents: [Function: bound ] },
_address: ‘0x59E7161646C3436DFdF5eBE617B4A172974B481e’,
_jsonInterface:
[ { constant: true,
inputs: [Array],
name: ‘votes’,
outputs: [Array],
payable: false,
stateMutability: ‘view’,
type: ‘function’,
signature: ‘0xd8bff5a5’ },
{ constant: true,
inputs: [],
name: ‘getPoll’,
outputs: [Array],
payable: false,
stateMutability: ‘view’,
type: ‘function’,
signature: ‘0x03c32278’ },
{ anonymous: false,
inputs: [Array],
name: ‘Voted’,
type: ‘event’,
signature: ‘0x4d99b957a2bc29a30ebd96a7be8e68fe50a3c70
1db28a91436490b7d53870ca4′ },
{ constant: false,
inputs: [Array],
name: ‘vote’,
outputs: [],
payable: false,
stateMutability: ‘nonpayable’,
type: ‘function’,
signature: ‘0x0121b93f’ } ] }
Dane wyjściowe pokazują różne właściwości kontraktu, który wdrożyliśmy w naszej prywatnej sieci. Najważniejszy jest adres kontraktu, pod którym umowa jest wdrażana, czyli
0x59E7161646C3436DFdF5eBE617B4A172974B481e.
Umowę ABI i adres można wykorzystać do wywołania funkcji w umowie. W następnej sekcji zbudujemy prostą aplikację internetową, która wywoła funkcję głosowania w tej umowie, pokazując, jak można przeprowadzić ankietę z poziomu interfejsu użytkownika.