Compilación y despliegue de Registrar.sol en red privada

Creé un contrato usando la consola go-ethereum, quiero implementar el registrador en una red privada. Descubrí una forma de compilar e implementar en https://github.com/ethereum/dapp-bin/tree/master/registrar

Pero no sé cómo compilar el contrato: Registrar.sol .

Respuestas (1)

Deberá compilar e implementar el código desde github.com/ethereum/dapp-bin/.../registrar .

Registrar.sol solo contiene una clase con las funciones de interfaz.

GlobalRegistrar.sol implementa la interfaz Registrar.sol.

Así que aquí hay una guía paso a paso para implementar y usar el GlobalRegistrarcontrato.

A continuación se muestra el código fuente de GlobalRegistrar.sol . Guárdelo en GlobalRegistrar.sol en su subdirectorio de trabajo:

//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;
}

Usando el stripCrLfscript en Cómo cargar el archivo fuente de Solidity en geth , aplané el código fuente usando el siguiente comando:

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;}'

Estoy ejecutando una red de desarrollo usando el siguiente comando (tengo mi contraseña en passwordfile):

geth --datadir ~/devdata --dev --mine --minerthreads 1 --unlock 0 --password ~/passwordfile console

Pego el código aplanado en la gethlínea de comando:

> 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

Y compila el código usando el siguiente comando:

> var globalRegistrarCompiled = web3.eth.compile.solidity(globalRegistrarSource);
Version: 0.3.5-0/RelWithDebInfo-Linux/g++/Interpreter

path: /usr/bin/solc
undefined

Puede ver la interfaz binaria de la aplicación utilizando los siguientes comandos. Solo mostraré la salida de GlobalRegistrar ya que ese contrato implementa todas las funciones necesarias:

> 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"
}]

Implemente el contrato en la cadena de bloques:

> 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]

Ahora registremos un propietario en nuestra cuenta en eth.accounts[0]:

> globalRegistrar.reserve.sendTransaction("BokkyPooBah", {from: eth.accounts[0]})
"0xf38d70f2b7b505954b07ea50ff5ef6d11af318ee9be9df0a1cf882b738f2e945"

> globalRegistrar.setAddress.sendTransaction("BokkyPooBah", eth.accounts[0], {from: eth.accounts[0]})
"0x259c7902f83ed7c05e866f8f4cc52d85487730bfc1b7433e8bf8eacaa3e81f24"

Pero actualmente recibo un error al consultar los datos:

> globalRegistrar.addr("BokkyPooBah")
"0x0000000000000000000000000000000000000000"
> globalRegistrar.owner("BokkyPooBah")
"0x0000000000000000000000000000000000000000"

Y la razón por la que no puedo registrar BokkyPooBah es porque tiene menos de 12 caracteres y requeriría una subasta. Así que aumentemos el nombre a uno de más de 12 caracteres:

> 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"

Consulte también https://ethereum.gitbooks.io/frontier-guide/content/registrar_services.html para obtener más información.