Я создал контракт с помощью консоли go-ethereum, я хочу развернуть регистратор в частной сети. Я нашел способ компиляции и развертывания в https://github.com/ethereum/dapp-bin/tree/master/registrar .
Но я не знаю, как составить контракт: Registrar.sol .
Вам нужно будет скомпилировать и развернуть код с github.com/ethereum/dapp-bin/.../registrar .
Registrar.sol содержит только класс с функциями интерфейса.
GlobalRegistrar.sol реализует интерфейс Registrar.sol.
GlobalRegistrar
контракта.Ниже приведен исходный код GlobalRegistrar.sol . Сохраните его в GlobalRegistrar.sol в вашем рабочем подкаталоге:
//sol
contract NameRegister {
function addr(string _name) constant returns (address o_owner);
function name(address _owner) constant returns (string o_name);
}
contract Registrar is NameRegister {
event Changed(string indexed name);
event ReverseChanged(address indexed addr, string indexed name);
function owner(string _name) constant returns (address o_owner);
function addr(string _name) constant returns (address o_address);
function subRegistrar(string _name) constant returns (address o_subRegistrar);
function content(string _name) constant returns (bytes32 o_content);
function name(address _owner) constant returns (string o_name);
}
contract AuctionSystem {
event AuctionEnded(string indexed _name, address _winner);
event NewBid(string indexed _name, address _bidder, uint _value);
/// Function that is called once an auction ends.
function onAuctionEnd(string _name) internal;
function bid(string _name, address _bidder, uint _value) internal {
var auction = m_auctions[_name];
if (auction.endDate > 0 && now > auction.endDate)
{
AuctionEnded(_name, auction.highestBidder);
onAuctionEnd(_name);
delete m_auctions[_name];
return;
}
if (msg.value > auction.highestBid)
{
// new bid on auction
auction.secondHighestBid = auction.highestBid;
auction.sumOfBids += _value;
auction.highestBid = _value;
auction.highestBidder = _bidder;
auction.endDate = now + c_biddingTime;
NewBid(_name, _bidder, _value);
}
}
uint constant c_biddingTime = 7 days;
struct Auction {
address highestBidder;
uint highestBid;
uint secondHighestBid;
uint sumOfBids;
uint endDate;
}
mapping(string => Auction) m_auctions;
}
contract GlobalRegistrar is Registrar, AuctionSystem {
struct Record {
address owner;
address primary;
address subRegistrar;
bytes32 content;
uint renewalDate;
}
uint constant c_renewalInterval = 1 years;
uint constant c_freeBytes = 12;
function Registrar() {
// TODO: Populate with hall-of-fame.
}
function() {
// prevent people from just sending funds to the registrar
throw;
}
function onAuctionEnd(string _name) internal {
var auction = m_auctions[_name];
var record = m_toRecord[_name];
if (record.owner != 0)
record.owner.send(auction.sumOfBids - auction.highestBid / 100);
else
auction.highestBidder.send(auction.highestBid - auction.secondHighestBid);
record.renewalDate = now + c_renewalInterval;
record.owner = auction.highestBidder;
Changed(_name);
}
function reserve(string _name) external {
if (bytes(_name).length == 0)
throw;
bool needAuction = requiresAuction(_name);
if (needAuction)
{
if (now < m_toRecord[_name].renewalDate)
throw;
bid(_name, msg.sender, msg.value);
}
else
{
Record record = m_toRecord[_name];
if (record.owner != 0)
throw;
m_toRecord[_name].owner = msg.sender;
Changed(_name);
}
}
function requiresAuction(string _name) internal returns (bool) {
return bytes(_name).length < c_freeBytes;
}
modifier onlyrecordowner(string _name) { if (m_toRecord[_name].owner == msg.sender) _ }
function setOwner(string _name, address _newOwner) onlyrecordowner(_name) {
m_toRecord[_name].owner = _newOwner;
Changed(_name);
}
function disown(string _name) onlyrecordowner(_name) {
if (stringsEqual(m_toName[m_toRecord[_name].primary], _name))
{
ReverseChanged(m_toRecord[_name].primary, "");
m_toName[m_toRecord[_name].primary] = "";
}
delete m_toRecord[_name];
Changed(_name);
}
function setName(string _name) {
if (m_toRecord[_name].primary == msg.sender)
{
ReverseChanged(msg.sender, _name);
m_toName[msg.sender] = _name;
}
}
function setAddress(string _name, address _a) onlyrecordowner(_name) {
m_toRecord[_name].primary = _a;
Changed(_name);
}
function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) {
m_toRecord[_name].subRegistrar = _registrar;
Changed(_name);
}
function setContent(string _name, bytes32 _content) onlyrecordowner(_name) {
m_toRecord[_name].content = _content;
Changed(_name);
}
function stringsEqual(string storage _a, string memory _b) internal returns (bool) {
bytes storage a = bytes(_a);
bytes memory b = bytes(_b);
if (a.length != b.length)
return false;
// @todo unroll this loop
for (uint i = 0; i < a.length; i ++)
if (a[i] != b[i])
return false;
return true;
}
function owner(string _name) constant returns (address) { return m_toRecord[_name].owner; }
function addr(string _name) constant returns (address) { return m_toRecord[_name].primary; }
function subRegistrar(string _name) constant returns (address) { return m_toRecord[_name].subRegistrar; }
function content(string _name) constant returns (bytes32) { return m_toRecord[_name].content; }
function name(address _addr) constant returns (string o_name) { return m_toName[_addr]; }
mapping (address => string) m_toName;
mapping (string => Record) m_toRecord;
}
Используя stripCrLf
сценарий из раздела Как загрузить исходный файл Solidity в geth , я сгладил исходный код с помощью следующей команды:
user@Kumquat:~/Registrar$ echo "var globalRegistrarSource='`stripCrLf GlobalRegistrar.sol`'"
var globalRegistrarSource='contract NameRegister { function addr(string _name) constant returns (address o_owner); function name(address _owner) constant returns (string o_name);}contract Registrar is NameRegister { event Changed(string indexed name); event ReverseChanged(address indexed addr, string indexed name); function owner(string _name) constant returns (address o_owner); function addr(string _name) constant returns (address o_address); function subRegistrar(string _name) constant returns (address o_subRegistrar); function content(string _name) constant returns (bytes32 o_content); function name(address _owner) constant returns (string o_name);}contract AuctionSystem { event AuctionEnded(string indexed _name, address _winner); event NewBid(string indexed _name, address _bidder, uint _value); function onAuctionEnd(string _name) internal; function bid(string _name, address _bidder, uint _value) internal { var auction = m_auctions[_name]; if (auction.endDate > 0 && now > auction.endDate) { AuctionEnded(_name, auction.highestBidder); onAuctionEnd(_name); delete m_auctions[_name]; return; } if (msg.value > auction.highestBid) { auction.secondHighestBid = auction.highestBid; auction.sumOfBids += _value; auction.highestBid = _value; auction.highestBidder = _bidder; auction.endDate = now + c_biddingTime; NewBid(_name, _bidder, _value); } } uint constant c_biddingTime = 7 days; struct Auction { address highestBidder; uint highestBid; uint secondHighestBid; uint sumOfBids; uint endDate; } mapping(string => Auction) m_auctions;}contract GlobalRegistrar is Registrar, AuctionSystem { struct Record { address owner; address primary; address subRegistrar; bytes32 content; uint renewalDate; } uint constant c_renewalInterval = 1 years; uint constant c_freeBytes = 12; function Registrar() { } function() { throw; } function onAuctionEnd(string _name) internal { var auction = m_auctions[_name]; var record = m_toRecord[_name]; if (record.owner != 0) record.owner.send(auction.sumOfBids - auction.highestBid / 100); else auction.highestBidder.send(auction.highestBid - auction.secondHighestBid); record.renewalDate = now + c_renewalInterval; record.owner = auction.highestBidder; Changed(_name); } function reserve(string _name) external { if (bytes(_name).length == 0) throw; bool needAuction = requiresAuction(_name); if (needAuction) { if (now < m_toRecord[_name].renewalDate) throw; bid(_name, msg.sender, msg.value); } else { Record record = m_toRecord[_name]; if (record.owner != 0) throw; m_toRecord[_name].owner = msg.sender; Changed(_name); } } function requiresAuction(string _name) internal returns (bool) { return bytes(_name).length < c_freeBytes; } modifier onlyrecordowner(string _name) { if (m_toRecord[_name].owner == msg.sender) _ } function setOwner(string _name, address _newOwner) onlyrecordowner(_name) { m_toRecord[_name].owner = _newOwner; Changed(_name); } function disown(string _name) onlyrecordowner(_name) { if (stringsEqual(m_toName[m_toRecord[_name].primary], _name)) { ReverseChanged(m_toRecord[_name].primary, ""); m_toName[m_toRecord[_name].primary] = ""; } delete m_toRecord[_name]; Changed(_name); } function setName(string _name) { if (m_toRecord[_name].primary == msg.sender) { ReverseChanged(msg.sender, _name); m_toName[msg.sender] = _name; } } function setAddress(string _name, address _a) onlyrecordowner(_name) { m_toRecord[_name].primary = _a; Changed(_name); } function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) { m_toRecord[_name].subRegistrar = _registrar; Changed(_name); } function setContent(string _name, bytes32 _content) onlyrecordowner(_name) { m_toRecord[_name].content = _content; Changed(_name); } function stringsEqual(string storage _a, string memory _b) internal returns (bool) { bytes storage a = bytes(_a); bytes memory b = bytes(_b); if (a.length != b.length) return false; for (uint i = 0; i < a.length; i ++) if (a[i] != b[i]) return false; return true; } function owner(string _name) constant returns (address) { return m_toRecord[_name].owner; } function addr(string _name) constant returns (address) { return m_toRecord[_name].primary; } function subRegistrar(string _name) constant returns (address) { return m_toRecord[_name].subRegistrar; } function content(string _name) constant returns (bytes32) { return m_toRecord[_name].content; } function name(address _addr) constant returns (string o_name) { return m_toName[_addr]; } mapping (address => string) m_toName; mapping (string => Record) m_toRecord;}'
Я запускаю сеть разработчиков, используя следующую команду (у меня есть пароль passwordfile
):
geth --datadir ~/devdata --dev --mine --minerthreads 1 --unlock 0 --password ~/passwordfile console
Я вставляю плоский код в geth
командную строку:
> var globalRegistrarSource='contract NameRegister { function addr(string _name) constant returns (address o_owner); function name(address _owner) constant returns (string o_name);}contract Registrar is NameRegister { event Changed(string indexed name); event ReverseChanged(address indexed addr, string indexed name); function owner(string _name) constant returns (address o_owner); function addr(string _name) constant returns (address o_address); function subRegistrar(string _name) constant returns (address o_subRegistrar); function content(string _name) constant returns (bytes32 o_content); function name(address _owner) constant returns (string o_name);}contract AuctionSystem { event AuctionEnded(string indexed _name, address _winner); event NewBid(string indexed _name, address _bidder, uint _value); function onAuctionEnd(string _name) internal; function bid(string _name, address _bidder, uint _value) internal { var auction = m_auctions[_name]; if (auction.endDate > 0 && now > auction.endDate) { AuctionEnded(_name, auction.highestBidder); onAuctionEnd(_name); delete m_auctions[_name]; return; } if (msg.value > auction.highestBid) { auction.secondHighestBid = auction.highestBid; auction.sumOfBids += _value; auction.highestBid = _value; auction.highestBidder = _bidder; auction.endDate = now + c_biddingTime; NewBid(_name, _bidder, _value); } } uint constant c_biddingTime = 7 days; struct Auction { address highestBidder; uint highestBid; uint secondHighestBid; uint sumOfBids; uint endDate; } mapping(string => Auction) m_auctions;}contract GlobalRegistrar is Registrar, AuctionSystem { struct Record { address owner; address primary; address subRegistrar; bytes32 content; uint renewalDate; } uint constant c_renewalInterval = 1 years; uint constant c_freeBytes = 12; function Registrar() { } function() { throw; } function onAuctionEnd(string _name) internal { var auction = m_auctions[_name]; var record = m_toRecord[_name]; if (record.owner != 0) record.owner.send(auction.sumOfBids - auction.highestBid / 100); else auction.highestBidder.send(auction.highestBid - auction.secondHighestBid); record.renewalDate = now + c_renewalInterval; record.owner = auction.highestBidder; Changed(_name); } function reserve(string _name) external { if (bytes(_name).length == 0) throw; bool needAuction = requiresAuction(_name); if (needAuction) { if (now < m_toRecord[_name].renewalDate) throw; bid(_name, msg.sender, msg.value); } else { Record record = m_toRecord[_name]; if (record.owner != 0) throw; m_toRecord[_name].owner = msg.sender; Changed(_name); } } function requiresAuction(string _name) internal returns (bool) { return bytes(_name).length < c_freeBytes; } modifier onlyrecordowner(string _name) { if (m_toRecord[_name].owner == msg.sender) _ } function setOwner(string _name, address _newOwner) onlyrecordowner(_name) { m_toRecord[_name].owner = _newOwner; Changed(_name); } function disown(string _name) onlyrecordowner(_name) { if (stringsEqual(m_toName[m_toRecord[_name].primary], _name)) { ReverseChanged(m_toRecord[_name].primary, ""); m_toName[m_toRecord[_name].primary] = ""; } delete m_toRecord[_name]; Changed(_name); } function setName(string _name) { if (m_toRecord[_name].primary == msg.sender) { ReverseChanged(msg.sender, _name); m_toName[msg.sender] = _name; } } function setAddress(string _name, address _a) onlyrecordowner(_name) { m_toRecord[_name].primary = _a; Changed(_name); } function setSubRegistrar(string _name, address _registrar) onlyrecordowner(_name) { m_toRecord[_name].subRegistrar = _registrar; Changed(_name); } function setContent(string _name, bytes32 _content) onlyrecordowner(_name) { m_toRecord[_name].content = _content; Changed(_name); } function stringsEqual(string storage _a, string memory _b) internal returns (bool) { bytes storage a = bytes(_a); bytes memory b = bytes(_b); if (a.length != b.length) return false; for (uint i = 0; i < a.length; i ++) if (a[i] != b[i]) return false; return true; } function owner(string _name) constant returns (address) { return m_toRecord[_name].owner; } function addr(string _name) constant returns (address) { return m_toRecord[_name].primary; } function subRegistrar(string _name) constant returns (address) { return m_toRecord[_name].subRegistrar; } function content(string _name) constant returns (bytes32) { return m_toRecord[_name].content; } function name(address _addr) constant returns (string o_name) { return m_toName[_addr]; } mapping (address => string) m_toName; mapping (string => Record) m_toRecord;}'
undefined
И скомпилируйте код с помощью следующей команды:
> var globalRegistrarCompiled = web3.eth.compile.solidity(globalRegistrarSource);
Version: 0.3.5-0/RelWithDebInfo-Linux/g++/Interpreter
path: /usr/bin/solc
undefined
Вы можете просмотреть двоичный интерфейс приложения, используя следующие команды. Я буду отображать только вывод GlobalRegistrar, так как этот контракт реализует все необходимые функции:
> globalRegistrarCompiled.NameRegister.info.abiDefinition
...
> globalRegistrarCompiled.Registrar.info.abiDefinition
...
> globalRegistrarCompiled.AuctionSystem.info.abiDefinition
...
> globalRegistrarCompiled.GlobalRegistrar.info.abiDefinition
[{
constant: true,
inputs: [{
name: "_addr",
type: "address"
}],
name: "name",
outputs: [{
name: "o_name",
type: "string"
}],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}],
name: "disown",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}, {
name: "_newOwner",
type: "address"
}],
name: "setOwner",
outputs: [],
type: "function"
}, {
constant: true,
inputs: [{
name: "_name",
type: "string"
}],
name: "addr",
outputs: [{
name: "",
type: "address"
}],
type: "function"
}, {
constant: true,
inputs: [{
name: "_name",
type: "string"
}],
name: "subRegistrar",
outputs: [{
name: "",
type: "address"
}],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}, {
name: "_a",
type: "address"
}],
name: "setAddress",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}],
name: "reserve",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [],
name: "Registrar",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}],
name: "setName",
outputs: [],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}, {
name: "_registrar",
type: "address"
}],
name: "setSubRegistrar",
outputs: [],
type: "function"
}, {
constant: true,
inputs: [{
name: "_name",
type: "string"
}],
name: "content",
outputs: [{
name: "",
type: "bytes32"
}],
type: "function"
}, {
constant: true,
inputs: [{
name: "_name",
type: "string"
}],
name: "owner",
outputs: [{
name: "",
type: "address"
}],
type: "function"
}, {
constant: false,
inputs: [{
name: "_name",
type: "string"
}, {
name: "_content",
type: "bytes32"
}],
name: "setContent",
outputs: [],
type: "function"
}, {
anonymous: false,
inputs: [{
indexed: true,
name: "_name",
type: "string"
}, {
indexed: false,
name: "_winner",
type: "address"
}],
name: "AuctionEnded",
type: "event"
}, {
anonymous: false,
inputs: [{
indexed: true,
name: "_name",
type: "string"
}, {
indexed: false,
name: "_bidder",
type: "address"
}, {
indexed: false,
name: "_value",
type: "uint256"
}],
name: "NewBid",
type: "event"
}, {
anonymous: false,
inputs: [{
indexed: true,
name: "name",
type: "string"
}],
name: "Changed",
type: "event"
}, {
anonymous: false,
inputs: [{
indexed: true,
name: "addr",
type: "address"
}, {
indexed: true,
name: "name",
type: "string"
}],
name: "ReverseChanged",
type: "event"
}]
Разверните контракт на блокчейне:
> var globalRegistrarContract = web3.eth.contract(globalRegistrarCompiled.GlobalRegistrar.info.abiDefinition);
undefined
> var globalRegistrar = globalRegistrarContract.new({
from:web3.eth.accounts[0],
data: globalRegistrarCompiled.GlobalRegistrar.code, gas: 2000000},
function(e, contract) {
if (!e) {
if (!contract.address) {
console.log("Contract transaction send: TransactionHash: " +
contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
...
Contract mined! Address: 0x6232a8cabd6171c8be20c2e5f32766c3805bdb39
[object Object]
Давайте теперь зарегистрируем владельца нашей учетной записи на eth.accounts[0]:
> globalRegistrar.reserve.sendTransaction("BokkyPooBah", {from: eth.accounts[0]})
"0xf38d70f2b7b505954b07ea50ff5ef6d11af318ee9be9df0a1cf882b738f2e945"
> globalRegistrar.setAddress.sendTransaction("BokkyPooBah", eth.accounts[0], {from: eth.accounts[0]})
"0x259c7902f83ed7c05e866f8f4cc52d85487730bfc1b7433e8bf8eacaa3e81f24"
Но в настоящее время я получаю сообщение об ошибке при запросе данных:
> globalRegistrar.addr("BokkyPooBah")
"0x0000000000000000000000000000000000000000"
> globalRegistrar.owner("BokkyPooBah")
"0x0000000000000000000000000000000000000000"
И причина, по которой я не могу зарегистрировать BokkyPooBah, заключается в том, что он содержит менее 12 символов и потребует проведения аукциона. Итак, давайте увеличим имя до одного длиннее 12 символов:
> globalRegistrar.reserve.sendTransaction("BokkyPooBahWuzHere", {from: eth.accounts[0]})
"0x0d194774f6e13ac0860a945aa96336a595cce61220fca67c1b7600b9538ff6e3"
> globalRegistrar.setAddress.sendTransaction("BokkyPooBahWuzHere", eth.accounts[0], {from: eth.accounts[0]})
"0xbc88acc79591b83c941e3d14e42a051d3c2ec8868a29ed195662b3e8072589db"
> globalRegistrar.owner("BokkyPooBahWuzHere")
"0xa7857047907d53a2e494d5f311b4b586dc6a96d2"
> globalRegistrar.addr("BokkyPooBahWuzHere")
"0xa7857047907d53a2e494d5f311b4b586dc6a96d2"
См. также https://ethereum.gitbooks.io/frontier-guide/content/registrar_services.html для получения дополнительной информации.