Validator Only Contract¶
Warning
Lity supports Validator Only Contracts after lity v1.2.2.
Lity supports Validator Only Contracts after v1.2.2. By providing the built-in function called isValidator and special opcode OpIsValidator, Lity can check whether an address is a validator of CyberMiles blockchain. With this feature, smart contract developers can create trusted smart contracts that can only be modified by the validators.
A common use case is to serve as oracles to provide trusted states.
isValidator Grammar¶
isValidator(<address>) returns (bool returnValue);
// isValidator is a built-in function provided by Lity.
// isValidator only takes one parameter, an address, to check whether this address is a validtor.
// If the address is a validator => return true
// Otherwise => return false
Examples¶
BTCRelay¶
Here we use BTCRelay contract as an example to show how validator only contract works. BTCRelay is a contract that store BTC headers and verify BTC transactions.
Download and compile it using lityc
(version >= 1.2.2):
$ wget https://raw.githubusercontent.com/CyberMiles/smart_contracts/master/BTCRelay/BTCRelay.sol
$ lityc --abi --bin -o output BTCRelay.sol
and then we could deploy it to Travis chain:
$ travis attach http://localhost:8545
// Prepare accounts
> validatorAccount = web3.cmt.accounts[0]
"0x7eff122b94897ea5b0e2a9abf47b86337fafebdc"
> normalAccount = personal.newAccount('test')
"0x34bb135d77771038a2fda3aa7cd5dc3fb4cc6abd"
> personal.unlockAccount(validatorAccount, '1234', 86400)
true
> personal.unlockAccount(normalAccount, 'test', 86400)
true
> cmt.sendTransaction({from: validatorAccount, to: normalAccount, value: 100000000000000000})
// Deploy contract
> abi = <...>
> bytecode = <...>
> contract = web3.cmt.contract(abi);
> btcrelay = contract.new(
{
from: web3.cmt.accounts[0],
data: bytecode,
gas: "4700000"
},
function(e, contract) {
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
}
);
// Contract mined! address: 0x05ea0f73204ea39d7231706a49c174a20380cfec transactionHash: 0x1acbd651d91f1edd3520da59dfda077c9f2ca3bbd9aa09bbc3304ec76a8b41ef
Now we try to call storeHeader
function using both validatorAccount
and normalAccount
> height = 125552
> header = '0x0x0100000081cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000e320b6c2fffc8d750423db8b1eb942ae710e951ed797f7affc8892b0f1fc122bc7f5d74df2b9441a42a14695'
// Send transaction with validator account
> tx = btcrelay.storeHeader.sendTransaction(header, height, {from: validatorAccount, gas: "300000"})
"0xe5d83d5ca82a00b6311ec9b8c0bab4df3f7a62971231791182686ba8f594b7eb"
> cmt.getTransactionReceipt(tx)
{
blockHash: "0x91186a59e8fb19c1db440ab0697266fb3407a10844342278a55e1dcf0eb501e1",
blockNumber: 72145,
contractAddress: null,
cumulativeGasUsed: 140024,
from: "0x7eff122b94897ea5b0e2a9abf47b86337fafebdc",
gasUsed: 140024,
logs: [{
address: "0x05ea0f73204ea39d7231706a49c174a20380cfec",
blockHash: "0x91186a59e8fb19c1db440ab0697266fb3407a10844342278a55e1dcf0eb501e1",
blockNumber: 72145,
data: "0x00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d",
logIndex: 0,
removed: false,
topics: ["0xf82c50f1848136e6c140b186ea0c768b7deda5efffe42c25e96336a90b26c744"],
transactionHash: "0xe5d83d5ca82a00b6311ec9b8c0bab4df3f7a62971231791182686ba8f594b7eb",
transactionIndex: 0
}],
logsBloom: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000800000
00000000000000000000000000000000000000000000001000000000000000100020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000",
status: "0x1",
to: "0x05ea0f73204ea39d7231706a49c174a20380cfec",
transactionHash: "0xe5d83d5ca82a00b6311ec9b8c0bab4df3f7a62971231791182686ba8f594b7eb",
transactionIndex: 0
}
// Send transaction with normal account
> tx = btcrelay.storeHeader.sendTransaction(header, height, {from: normalAccount, gas: "300000"})
"0xed05e610feae32bd51931b9d0068104dc60a9595590d17b73e1916c2288b0cf9"
> cmt.getTransactionReceipt(tx)
{
blockHash: "0x611671eff48e414706daa66f1fcc404428832dd79c2b6a9481a28f46ef93a430",
blockNumber: 72173,
contractAddress: null,
cumulativeGasUsed: 27466,
from: "0x34bb135d77771038a2fda3aa7cd5dc3fb4cc6abd",
gasUsed: 27466,
logs: [],
logsBloom: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000",
status: "0x0",
to: "0x05ea0f73204ea39d7231706a49c174a20380cfec",
transactionHash: "0xed05e610feae32bd51931b9d0068104dc60a9595590d17b73e1916c2288b0cf9",
transactionIndex: 0
}
We could see when sending transaction using validatorAccount
, the transactions triggered storeHeader
function successfully and emit log.
Log data 0x00000000000000001e8d6829a8a21adc5d38d0a473b144b6765798e61f98bd1d
is returned hash of block header.
When sending transaction using normalAccount
, it could not pass validatorOnly()
check and failed.
If you want to interact with BTCRelay contract, you could check our fetchd as an example to fetch and store BTC headers.