You will have to compile and deploy the code from github.com/ethereum/dapp-bin/.../registrar.
Registrar.sol only contains a class with the interface functions.
GlobalRegistrar.sol implements the Registrar.sol interface.
So here is a step-by-step guide to deploying and using the GlobalRegistrar
contract.
Following is the source code for GlobalRegistrar.sol. Save it to GlobalRegistrar.sol in your working subdirectory:
//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;
}
Using the stripCrLf
script in How to load Solidity source file into geth, I've flattened the source code using the following command:
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;}'
I'm running a dev network using the following command (I have my password in passwordfile
):
geth --datadir ~/devdata --dev --mine --minerthreads 1 --unlock 0 --password ~/passwordfile console
I paste the flattened code in the geth
command line:
> 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
And compile the code using the following command:
> var globalRegistrarCompiled = web3.eth.compile.solidity(globalRegistrarSource);
Version: 0.3.5-0/RelWithDebInfo-Linux/g++/Interpreter
path: /usr/bin/solc
undefined
You can view the Application Binary Interface using the following commands. I will only display the GlobalRegistrar output as that contract implements all the necessary functions:
> 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"
}]
Deploy the contract on the blockchain:
> 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]
Let's now register an owner to our account at eth.accounts[0]:
> globalRegistrar.reserve.sendTransaction("BokkyPooBah", {from: eth.accounts[0]})
"0xf38d70f2b7b505954b07ea50ff5ef6d11af318ee9be9df0a1cf882b738f2e945"
> globalRegistrar.setAddress.sendTransaction("BokkyPooBah", eth.accounts[0], {from: eth.accounts[0]})
"0x259c7902f83ed7c05e866f8f4cc52d85487730bfc1b7433e8bf8eacaa3e81f24"
But I'm getting an error currently when querying the data:
> globalRegistrar.addr("BokkyPooBah")
"0x0000000000000000000000000000000000000000"
> globalRegistrar.owner("BokkyPooBah")
"0x0000000000000000000000000000000000000000"
And the reason I cannot register BokkyPooBah is because it is less than 12 characters long, and would require an auction. So let's increase the name to one longer than 12 characters:
> 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"
See also https://ethereum.gitbooks.io/frontier-guide/content/registrar_services.html for further information.