aboutsummaryrefslogtreecommitdiffstats
path: root/contracts
diff options
context:
space:
mode:
Diffstat (limited to 'contracts')
-rw-r--r--contracts/chequebook/api.go68
-rw-r--r--contracts/chequebook/cheque.go642
-rw-r--r--contracts/chequebook/cheque_test.go528
-rw-r--r--contracts/chequebook/contract/chequebook.go541
-rw-r--r--contracts/chequebook/contract/chequebook.sol45
-rw-r--r--contracts/chequebook/contract/code.go5
-rw-r--r--contracts/chequebook/gencode.go71
-rw-r--r--contracts/ens/README.md20
-rw-r--r--contracts/ens/contract/ens.go921
-rw-r--r--contracts/ens/contract/ens.sol226
-rw-r--r--contracts/ens/ens.go178
-rw-r--r--contracts/ens/ens_test.go67
-rw-r--r--contracts/release/contract.go432
-rw-r--r--contracts/release/contract.sol249
-rw-r--r--contracts/release/contract_test.go374
-rw-r--r--contracts/release/release.go152
16 files changed, 4519 insertions, 0 deletions
diff --git a/contracts/chequebook/api.go b/contracts/chequebook/api.go
new file mode 100644
index 000000000..b2b2365f3
--- /dev/null
+++ b/contracts/chequebook/api.go
@@ -0,0 +1,68 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package chequebook
+
+import (
+ "errors"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+)
+
+const Version = "1.0"
+
+var errNoChequebook = errors.New("no chequebook")
+
+type Api struct {
+ chequebookf func() *Chequebook
+}
+
+func NewApi(ch func() *Chequebook) *Api {
+ return &Api{ch}
+}
+
+func (self *Api) Balance() (string, error) {
+ ch := self.chequebookf()
+ if ch == nil {
+ return "", errNoChequebook
+ }
+ return ch.Balance().String(), nil
+}
+
+func (self *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *Cheque, err error) {
+ ch := self.chequebookf()
+ if ch == nil {
+ return nil, errNoChequebook
+ }
+ return ch.Issue(beneficiary, amount)
+}
+
+func (self *Api) Cash(cheque *Cheque) (txhash string, err error) {
+ ch := self.chequebookf()
+ if ch == nil {
+ return "", errNoChequebook
+ }
+ return ch.Cash(cheque)
+}
+
+func (self *Api) Deposit(amount *big.Int) (txhash string, err error) {
+ ch := self.chequebookf()
+ if ch == nil {
+ return "", errNoChequebook
+ }
+ return ch.Deposit(amount)
+}
diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go
new file mode 100644
index 000000000..5ece1391b
--- /dev/null
+++ b/contracts/chequebook/cheque.go
@@ -0,0 +1,642 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package chequebook package wraps the 'chequebook' Ethereum smart contract.
+//
+// The functions in this package allow using chequebook for
+// issuing, receiving, verifying cheques in ether; (auto)cashing cheques in ether
+// as well as (auto)depositing ether to the chequebook contract.
+package chequebook
+
+//go:generate abigen --sol contract/chequebook.sol --pkg contract --out contract/chequebook.go
+//go:generate go run ./gencode.go
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "math/big"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/contracts/chequebook/contract"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/swarm/services/swap/swap"
+ "golang.org/x/net/context"
+)
+
+// TODO(zelig): watch peer solvency and notify of bouncing cheques
+// TODO(zelig): enable paying with cheque by signing off
+
+// Some functionality require interacting with the blockchain:
+// * setting current balance on peer's chequebook
+// * sending the transaction to cash the cheque
+// * depositing ether to the chequebook
+// * watching incoming ether
+
+var (
+ gasToCash = big.NewInt(2000000) // gas cost of a cash transaction using chequebook
+ // gasToDeploy = big.NewInt(3000000)
+)
+
+// Backend wraps all methods required for chequebook operation.
+type Backend interface {
+ bind.ContractBackend
+ TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
+ BalanceAt(ctx context.Context, address common.Address, blockNum *big.Int) (*big.Int, error)
+}
+
+// Cheque represents a payment promise to a single beneficiary.
+type Cheque struct {
+ Contract common.Address // address of chequebook, needed to avoid cross-contract submission
+ Beneficiary common.Address
+ Amount *big.Int // cumulative amount of all funds sent
+ Sig []byte // signature Sign(Keccak256(contract, beneficiary, amount), prvKey)
+}
+
+func (self *Cheque) String() string {
+ return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", self.Contract.Hex(), self.Beneficiary.Hex(), self.Amount, self.Sig)
+}
+
+type Params struct {
+ ContractCode, ContractAbi string
+}
+
+var ContractParams = &Params{contract.ChequebookBin, contract.ChequebookABI}
+
+// Chequebook can create and sign cheques from a single contract to multiple beneficiaries.
+// It is the outgoing payment handler for peer to peer micropayments.
+type Chequebook struct {
+ path string // path to chequebook file
+ prvKey *ecdsa.PrivateKey // private key to sign cheque with
+ lock sync.Mutex //
+ backend Backend // blockchain API
+ quit chan bool // when closed causes autodeposit to stop
+ owner common.Address // owner address (derived from pubkey)
+ contract *contract.Chequebook // abigen binding
+ session *contract.ChequebookSession // abigen binding with Tx Opts
+
+ // persisted fields
+ balance *big.Int // not synced with blockchain
+ contractAddr common.Address // contract address
+ sent map[common.Address]*big.Int //tallies for beneficiarys
+
+ txhash string // tx hash of last deposit tx
+ threshold *big.Int // threshold that triggers autodeposit if not nil
+ buffer *big.Int // buffer to keep on top of balance for fork protection
+}
+
+func (self *Chequebook) String() string {
+ return fmt.Sprintf("contract: %s, owner: %s, balance: %v, signer: %x", self.contractAddr.Hex(), self.owner.Hex(), self.balance, self.prvKey.PublicKey)
+}
+
+// NewChequebook creates a new Chequebook.
+func NewChequebook(path string, contractAddr common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) {
+ balance := new(big.Int)
+ sent := make(map[common.Address]*big.Int)
+
+ chbook, err := contract.NewChequebook(contractAddr, backend)
+ if err != nil {
+ return nil, err
+ }
+ transactOpts := bind.NewKeyedTransactor(prvKey)
+ session := &contract.ChequebookSession{
+ Contract: chbook,
+ TransactOpts: *transactOpts,
+ }
+
+ self = &Chequebook{
+ prvKey: prvKey,
+ balance: balance,
+ contractAddr: contractAddr,
+ sent: sent,
+ path: path,
+ backend: backend,
+ owner: transactOpts.From,
+ contract: chbook,
+ session: session,
+ }
+
+ if (contractAddr != common.Address{}) {
+ self.setBalanceFromBlockChain()
+ glog.V(logger.Detail).Infof("new chequebook initialised from %s (owner: %v, balance: %s)", contractAddr.Hex(), self.owner.Hex(), self.balance.String())
+ }
+ return
+}
+
+func (self *Chequebook) setBalanceFromBlockChain() {
+ balance, err := self.backend.BalanceAt(context.TODO(), self.contractAddr, nil)
+ if err != nil {
+ glog.V(logger.Error).Infof("can't get balance: %v", err)
+ } else {
+ self.balance.Set(balance)
+ }
+}
+
+// LoadChequebook loads a chequebook from disk (file path).
+func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend, checkBalance bool) (self *Chequebook, err error) {
+ var data []byte
+ data, err = ioutil.ReadFile(path)
+ if err != nil {
+ return
+ }
+
+ self, _ = NewChequebook(path, common.Address{}, prvKey, backend)
+
+ err = json.Unmarshal(data, self)
+ if err != nil {
+ return nil, err
+ }
+ if checkBalance {
+ self.setBalanceFromBlockChain()
+ }
+
+ glog.V(logger.Detail).Infof("loaded chequebook (%s, owner: %v, balance: %v) initialised from %v", self.contractAddr.Hex(), self.owner.Hex(), self.balance, path)
+
+ return
+}
+
+// chequebookFile is the JSON representation of a chequebook.
+type chequebookFile struct {
+ Balance string
+ Contract string
+ Owner string
+ Sent map[string]string
+}
+
+// UnmarshalJSON deserialises a chequebook.
+func (self *Chequebook) UnmarshalJSON(data []byte) error {
+ var file chequebookFile
+ err := json.Unmarshal(data, &file)
+ if err != nil {
+ return err
+ }
+ _, ok := self.balance.SetString(file.Balance, 10)
+ if !ok {
+ return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance)
+ }
+ self.contractAddr = common.HexToAddress(file.Contract)
+ for addr, sent := range file.Sent {
+ self.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10)
+ if !ok {
+ return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent)
+ }
+ }
+ return nil
+}
+
+// MarshalJSON serialises a chequebook.
+func (self *Chequebook) MarshalJSON() ([]byte, error) {
+ var file = &chequebookFile{
+ Balance: self.balance.String(),
+ Contract: self.contractAddr.Hex(),
+ Owner: self.owner.Hex(),
+ Sent: make(map[string]string),
+ }
+ for addr, sent := range self.sent {
+ file.Sent[addr.Hex()] = sent.String()
+ }
+ return json.Marshal(file)
+}
+
+// Save persists the chequebook on disk, remembering balance, contract address and
+// cumulative amount of funds sent for each beneficiary.
+func (self *Chequebook) Save() (err error) {
+ data, err := json.MarshalIndent(self, "", " ")
+ if err != nil {
+ return err
+ }
+ glog.V(logger.Detail).Infof("saving chequebook (%s) to %v", self.contractAddr.Hex(), self.path)
+
+ return ioutil.WriteFile(self.path, data, os.ModePerm)
+}
+
+// Stop quits the autodeposit go routine to terminate
+func (self *Chequebook) Stop() {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ if self.quit != nil {
+ close(self.quit)
+ self.quit = nil
+ }
+}
+
+// Issue creates a cheque signed by the chequebook owner's private key. The
+// signer commits to a contract (one that they own), a beneficiary and amount.
+func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+
+ if amount.Cmp(common.Big0) <= 0 {
+ return nil, fmt.Errorf("amount must be greater than zero (%v)", amount)
+ }
+ if self.balance.Cmp(amount) < 0 {
+ err = fmt.Errorf("insufficent funds to issue cheque for amount: %v. balance: %v", amount, self.balance)
+ } else {
+ var sig []byte
+ sent, found := self.sent[beneficiary]
+ if !found {
+ sent = new(big.Int)
+ self.sent[beneficiary] = sent
+ }
+ sum := new(big.Int).Set(sent)
+ sum.Add(sum, amount)
+
+ sig, err = crypto.Sign(sigHash(self.contractAddr, beneficiary, sum), self.prvKey)
+ if err == nil {
+ ch = &Cheque{
+ Contract: self.contractAddr,
+ Beneficiary: beneficiary,
+ Amount: sum,
+ Sig: sig,
+ }
+ sent.Set(sum)
+ self.balance.Sub(self.balance, amount) // subtract amount from balance
+ }
+ }
+
+ // auto deposit if threshold is set and balance is less then threshold
+ // note this is called even if issueing cheque fails
+ // so we reattempt depositing
+ if self.threshold != nil {
+ if self.balance.Cmp(self.threshold) < 0 {
+ send := new(big.Int).Sub(self.buffer, self.balance)
+ self.deposit(send)
+ }
+ }
+
+ return
+}
+
+// Cash is a convenience method to cash any cheque.
+func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) {
+ return ch.Cash(self.session)
+}
+
+// data to sign: contract address, beneficiary, cumulative amount of funds ever sent
+func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte {
+ bigamount := sum.Bytes()
+ if len(bigamount) > 32 {
+ return nil
+ }
+ var amount32 [32]byte
+ copy(amount32[32-len(bigamount):32], bigamount)
+ input := append(contract.Bytes(), beneficiary.Bytes()...)
+ input = append(input, amount32[:]...)
+ return crypto.Keccak256(input)
+}
+
+// Balance returns the current balance of the chequebook.
+func (self *Chequebook) Balance() *big.Int {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ return new(big.Int).Set(self.balance)
+}
+
+// Owner returns the owner account of the chequebook.
+func (self *Chequebook) Owner() common.Address {
+ return self.owner
+}
+
+// Address returns the on-chain contract address of the chequebook.
+func (self *Chequebook) Address() common.Address {
+ return self.contractAddr
+}
+
+// Deposit deposits money to the chequebook account.
+func (self *Chequebook) Deposit(amount *big.Int) (string, error) {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ return self.deposit(amount)
+}
+
+// deposit deposits amount to the chequebook account.
+// The caller must hold self.lock.
+func (self *Chequebook) deposit(amount *big.Int) (string, error) {
+ // since the amount is variable here, we do not use sessions
+ depositTransactor := bind.NewKeyedTransactor(self.prvKey)
+ depositTransactor.Value = amount
+ chbookRaw := &contract.ChequebookRaw{Contract: self.contract}
+ tx, err := chbookRaw.Transfer(depositTransactor)
+ if err != nil {
+ glog.V(logger.Warn).Infof("error depositing %d wei to chequebook (%s, balance: %v, target: %v): %v", amount, self.contractAddr.Hex(), self.balance, self.buffer, err)
+ return "", err
+ }
+ // assume that transaction is actually successful, we add the amount to balance right away
+ self.balance.Add(self.balance, amount)
+ glog.V(logger.Detail).Infof("deposited %d wei to chequebook (%s, balance: %v, target: %v)", amount, self.contractAddr.Hex(), self.balance, self.buffer)
+ return tx.Hash().Hex(), nil
+}
+
+// AutoDeposit (re)sets interval time and amount which triggers sending funds to the
+// chequebook. Contract backend needs to be set if threshold is not less than buffer, then
+// deposit will be triggered on every new cheque issued.
+func (self *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ self.threshold = threshold
+ self.buffer = buffer
+ self.autoDeposit(interval)
+}
+
+// autoDeposit starts a goroutine that periodically sends funds to the chequebook
+// contract caller holds the lock the go routine terminates if Chequebook.quit is closed.
+func (self *Chequebook) autoDeposit(interval time.Duration) {
+ if self.quit != nil {
+ close(self.quit)
+ self.quit = nil
+ }
+ // if threshold >= balance autodeposit after every cheque issued
+ if interval == time.Duration(0) || self.threshold != nil && self.buffer != nil && self.threshold.Cmp(self.buffer) >= 0 {
+ return
+ }
+
+ ticker := time.NewTicker(interval)
+ self.quit = make(chan bool)
+ quit := self.quit
+ go func() {
+ FOR:
+ for {
+ select {
+ case <-quit:
+ break FOR
+ case <-ticker.C:
+ self.lock.Lock()
+ if self.balance.Cmp(self.buffer) < 0 {
+ amount := new(big.Int).Sub(self.buffer, self.balance)
+ txhash, err := self.deposit(amount)
+ if err == nil {
+ self.txhash = txhash
+ }
+ }
+ self.lock.Unlock()
+ }
+ }
+ }()
+ return
+}
+
+// Outbox can issue cheques from a single contract to a single beneficiary.
+type Outbox struct {
+ chequeBook *Chequebook
+ beneficiary common.Address
+}
+
+// NewOutbox creates an outbox.
+func NewOutbox(chbook *Chequebook, beneficiary common.Address) *Outbox {
+ return &Outbox{chbook, beneficiary}
+}
+
+// Issue creates cheque.
+func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) {
+ return self.chequeBook.Issue(self.beneficiary, amount)
+}
+
+// AutoDeposit enables auto-deposits on the underlying chequebook.
+func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
+ self.chequeBook.AutoDeposit(interval, threshold, buffer)
+}
+
+// Stop helps satisfy the swap.OutPayment interface.
+func (self *Outbox) Stop() {}
+
+// String implements fmt.Stringer.
+func (self *Outbox) String() string {
+ return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.chequeBook.Address().Hex(), self.beneficiary.Hex(), self.chequeBook.Balance())
+}
+
+// Inbox can deposit, verify and cash cheques from a single contract to a single
+// beneficiary. It is the incoming payment handler for peer to peer micropayments.
+type Inbox struct {
+ lock sync.Mutex
+ contract common.Address // peer's chequebook contract
+ beneficiary common.Address // local peer's receiving address
+ sender common.Address // local peer's address to send cashing tx from
+ signer *ecdsa.PublicKey // peer's public key
+ txhash string // tx hash of last cashing tx
+ abigen bind.ContractBackend // blockchain API
+ session *contract.ChequebookSession // abi contract backend with tx opts
+ quit chan bool // when closed causes autocash to stop
+ maxUncashed *big.Int // threshold that triggers autocashing
+ cashed *big.Int // cumulative amount cashed
+ cheque *Cheque // last cheque, nil if none yet received
+}
+
+// NewInbox creates an Inbox. An Inboxes is not persisted, the cumulative sum is updated
+// from blockchain when first cheque is received.
+func NewInbox(prvKey *ecdsa.PrivateKey, contractAddr, beneficiary common.Address, signer *ecdsa.PublicKey, abigen bind.ContractBackend) (self *Inbox, err error) {
+ if signer == nil {
+ return nil, fmt.Errorf("signer is null")
+ }
+ chbook, err := contract.NewChequebook(contractAddr, abigen)
+ if err != nil {
+ return nil, err
+ }
+ transactOpts := bind.NewKeyedTransactor(prvKey)
+ transactOpts.GasLimit = gasToCash
+ session := &contract.ChequebookSession{
+ Contract: chbook,
+ TransactOpts: *transactOpts,
+ }
+ sender := transactOpts.From
+
+ self = &Inbox{
+ contract: contractAddr,
+ beneficiary: beneficiary,
+ sender: sender,
+ signer: signer,
+ session: session,
+ cashed: new(big.Int).Set(common.Big0),
+ }
+ glog.V(logger.Detail).Infof("initialised inbox (%s -> %s) expected signer: %x", self.contract.Hex(), self.beneficiary.Hex(), crypto.FromECDSAPub(signer))
+ return
+}
+
+func (self *Inbox) String() string {
+ return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.contract.Hex(), self.beneficiary.Hex(), self.cheque.Amount)
+}
+
+// Stop quits the autocash goroutine.
+func (self *Inbox) Stop() {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ if self.quit != nil {
+ close(self.quit)
+ self.quit = nil
+ }
+}
+
+// Cash attempts to cash the current cheque.
+func (self *Inbox) Cash() (txhash string, err error) {
+ if self.cheque != nil {
+ txhash, err = self.cheque.Cash(self.session)
+ glog.V(logger.Detail).Infof("cashing cheque (total: %v) on chequebook (%s) sending to %v", self.cheque.Amount, self.contract.Hex(), self.beneficiary.Hex())
+ self.cashed = self.cheque.Amount
+ }
+ return
+}
+
+// AutoCash (re)sets maximum time and amount which triggers cashing of the last uncashed
+// cheque if maxUncashed is set to 0, then autocash on receipt.
+func (self *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) {
+ defer self.lock.Unlock()
+ self.lock.Lock()
+ self.maxUncashed = maxUncashed
+ self.autoCash(cashInterval)
+}
+
+// autoCash starts a loop that periodically clears the last check
+// if the peer is trusted. Clearing period could be 24h or a week.
+//
+// The caller must hold self.lock.
+func (self *Inbox) autoCash(cashInterval time.Duration) {
+ if self.quit != nil {
+ close(self.quit)
+ self.quit = nil
+ }
+ // if maxUncashed is set to 0, then autocash on receipt
+ if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Cmp(common.Big0) == 0 {
+ return
+ }
+
+ ticker := time.NewTicker(cashInterval)
+ self.quit = make(chan bool)
+ quit := self.quit
+ go func() {
+ FOR:
+ for {
+ select {
+ case <-quit:
+ break FOR
+ case <-ticker.C:
+ self.lock.Lock()
+ if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 {
+ txhash, err := self.Cash()
+ if err == nil {
+ self.txhash = txhash
+ }
+ }
+ self.lock.Unlock()
+ }
+ }
+ }()
+ return
+}
+
+// Receive is called to deposit the latest cheque to the incoming Inbox.
+// The given promise must be a *Cheque.
+func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) {
+ ch := promise.(*Cheque)
+
+ defer self.lock.Unlock()
+ self.lock.Lock()
+
+ var sum *big.Int
+ if self.cheque == nil {
+ // the sum is checked against the blockchain once a check is received
+ tally, err := self.session.Sent(self.beneficiary)
+ if err != nil {
+ return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err)
+ }
+ sum = tally
+ } else {
+ sum = self.cheque.Amount
+ }
+
+ amount, err := ch.Verify(self.signer, self.contract, self.beneficiary, sum)
+ var uncashed *big.Int
+ if err == nil {
+ self.cheque = ch
+
+ if self.maxUncashed != nil {
+ uncashed = new(big.Int).Sub(ch.Amount, self.cashed)
+ if self.maxUncashed.Cmp(uncashed) < 0 {
+ self.Cash()
+ }
+ }
+ glog.V(logger.Detail).Infof("received cheque of %v wei in inbox (%s, uncashed: %v)", amount, self.contract.Hex(), uncashed)
+ }
+
+ return amount, err
+}
+
+// Verify verifies cheque for signer, contract, beneficiary, amount, valid signature.
+func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) {
+ glog.V(logger.Detail).Infof("verify cheque: %v - sum: %v", self, sum)
+ if sum == nil {
+ return nil, fmt.Errorf("invalid amount")
+ }
+
+ if self.Beneficiary != beneficiary {
+ return nil, fmt.Errorf("beneficiary mismatch: %v != %v", self.Beneficiary.Hex(), beneficiary.Hex())
+ }
+ if self.Contract != contract {
+ return nil, fmt.Errorf("contract mismatch: %v != %v", self.Contract.Hex(), contract.Hex())
+ }
+
+ amount := new(big.Int).Set(self.Amount)
+ if sum != nil {
+ amount.Sub(amount, sum)
+ if amount.Cmp(common.Big0) <= 0 {
+ return nil, fmt.Errorf("incorrect amount: %v <= 0", amount)
+ }
+ }
+
+ pubKey, err := crypto.SigToPub(sigHash(self.Contract, beneficiary, self.Amount), self.Sig)
+ if err != nil {
+ return nil, fmt.Errorf("invalid signature: %v", err)
+ }
+ if !bytes.Equal(crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) {
+ return nil, fmt.Errorf("signer mismatch: %x != %x", crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey))
+ }
+ return amount, nil
+}
+
+// v/r/s representation of signature
+func sig2vrs(sig []byte) (v byte, r, s [32]byte) {
+ v = sig[64] + 27
+ copy(r[:], sig[:32])
+ copy(s[:], sig[32:64])
+ return
+}
+
+// Cash cashes the cheque by sending an Ethereum transaction.
+func (self *Cheque) Cash(session *contract.ChequebookSession) (string, error) {
+ v, r, s := sig2vrs(self.Sig)
+ tx, err := session.Cash(self.Beneficiary, self.Amount, v, r, s)
+ if err != nil {
+ return "", err
+ }
+ return tx.Hash().Hex(), nil
+}
+
+// ValidateCode checks that the on-chain code at address matches the expected chequebook
+// contract code. This is used to detect suicided chequebooks.
+func ValidateCode(ctx context.Context, b Backend, address common.Address) (ok bool, err error) {
+ code, err := b.CodeAt(ctx, address, nil)
+ if err != nil {
+ return false, err
+ }
+ return bytes.Equal(code, common.FromHex(contract.ContractDeployedCode)), nil
+}
diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go
new file mode 100644
index 000000000..e35a21cc5
--- /dev/null
+++ b/contracts/chequebook/cheque_test.go
@@ -0,0 +1,528 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package chequebook
+
+import (
+ "crypto/ecdsa"
+ "math/big"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/contracts/chequebook/contract"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+var (
+ key0, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ key1, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
+ key2, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
+ addr0 = crypto.PubkeyToAddress(key0.PublicKey)
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ addr2 = crypto.PubkeyToAddress(key2.PublicKey)
+)
+
+func newTestBackend() *backends.SimulatedBackend {
+ return backends.NewSimulatedBackend(
+ core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)},
+ core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)},
+ core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)},
+ )
+}
+
+func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
+ deployTransactor := bind.NewKeyedTransactor(prvKey)
+ deployTransactor.Value = amount
+ addr, _, _, err := contract.DeployChequebook(deployTransactor, backend)
+ if err != nil {
+ return common.Address{}, err
+ }
+ backend.Commit()
+ return addr, nil
+}
+
+func TestIssueAndReceive(t *testing.T) {
+ path := filepath.Join(os.TempDir(), "chequebook-test.json")
+ backend := newTestBackend()
+ addr0, err := deploy(key0, big.NewInt(0), backend)
+ if err != nil {
+ t.Fatalf("deploy contract: expected no error, got %v", err)
+ }
+ chbook, err := NewChequebook(path, addr0, key0, backend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ chbook.sent[addr1] = new(big.Int).SetUint64(42)
+ amount := common.Big1
+ ch, err := chbook.Issue(addr1, amount)
+ if err == nil {
+ t.Fatalf("expected insufficient funds error, got none")
+ }
+
+ chbook.balance = new(big.Int).Set(common.Big1)
+ if chbook.Balance().Cmp(common.Big1) != 0 {
+ t.Fatalf("expected: %v, got %v", "0", chbook.Balance())
+ }
+
+ ch, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ if chbook.Balance().Cmp(common.Big0) != 0 {
+ t.Errorf("expected: %v, got %v", "0", chbook.Balance())
+ }
+
+ chbox, err := NewInbox(key1, addr0, addr1, &key0.PublicKey, backend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ received, err := chbox.Receive(ch)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ if received.Cmp(big.NewInt(43)) != 0 {
+ t.Errorf("expected: %v, got %v", "43", received)
+ }
+
+}
+
+func TestCheckbookFile(t *testing.T) {
+ path := filepath.Join(os.TempDir(), "chequebook-test.json")
+ backend := newTestBackend()
+ chbook, err := NewChequebook(path, addr0, key0, backend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ chbook.sent[addr1] = new(big.Int).SetUint64(42)
+ chbook.balance = new(big.Int).Set(common.Big1)
+
+ chbook.Save()
+
+ chbook, err = LoadChequebook(path, key0, backend, false)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ if chbook.Balance().Cmp(common.Big1) != 0 {
+ t.Errorf("expected: %v, got %v", "0", chbook.Balance())
+ }
+
+ ch, err := chbook.Issue(addr1, common.Big1)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 {
+ t.Errorf("expected: %v, got %v", "0", ch.Amount)
+ }
+
+ err = chbook.Save()
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+}
+
+func TestVerifyErrors(t *testing.T) {
+ path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
+ backend := newTestBackend()
+ contr0, err := deploy(key0, common.Big2, backend)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ chbook0, err := NewChequebook(path0, contr0, key0, backend)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ path1 := filepath.Join(os.TempDir(), "chequebook-test-1.json")
+ contr1, err := deploy(key1, common.Big2, backend)
+ chbook1, err := NewChequebook(path1, contr1, key1, backend)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ chbook0.sent[addr1] = new(big.Int).SetUint64(42)
+ chbook0.balance = new(big.Int).Set(common.Big2)
+ chbook1.balance = new(big.Int).Set(common.Big1)
+ amount := common.Big1
+ ch0, err := chbook0.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ time.Sleep(5)
+ chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ received, err := chbox.Receive(ch0)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ if received.Cmp(big.NewInt(43)) != 0 {
+ t.Errorf("expected: %v, got %v", "43", received)
+ }
+
+ ch1, err := chbook0.Issue(addr2, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ received, err = chbox.Receive(ch1)
+ t.Logf("correct error: %v", err)
+ if err == nil {
+ t.Fatalf("expected receiver error, got none")
+ }
+
+ ch2, err := chbook1.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ received, err = chbox.Receive(ch2)
+ t.Logf("correct error: %v", err)
+ if err == nil {
+ t.Fatalf("expected sender error, got none")
+ }
+
+ _, err = chbook1.Issue(addr1, new(big.Int).SetInt64(-1))
+ t.Logf("correct error: %v", err)
+ if err == nil {
+ t.Fatalf("expected incorrect amount error, got none")
+ }
+
+ received, err = chbox.Receive(ch0)
+ t.Logf("correct error: %v", err)
+ if err == nil {
+ t.Fatalf("expected incorrect amount error, got none")
+ }
+
+}
+
+func TestDeposit(t *testing.T) {
+ path0 := filepath.Join(os.TempDir(), "chequebook-test-0.json")
+ backend := newTestBackend()
+ contr0, err := deploy(key0, new(big.Int), backend)
+ chbook, err := NewChequebook(path0, contr0, key0, backend)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+
+ balance := new(big.Int).SetUint64(42)
+ chbook.Deposit(balance)
+ backend.Commit()
+ if chbook.balance.Cmp(balance) != 0 {
+ t.Fatalf("expected balance %v, got %v", balance, chbook.balance)
+ }
+
+ amount := common.Big1
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ exp := new(big.Int).SetUint64(41)
+ if chbook.balance.Cmp(exp) != 0 {
+ t.Fatalf("expected balance %v, got %v", exp, chbook.balance)
+ }
+
+ // autodeposit on each issue
+ chbook.AutoDeposit(0, balance, balance)
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ if chbook.balance.Cmp(balance) != 0 {
+ t.Fatalf("expected balance %v, got %v", balance, chbook.balance)
+ }
+
+ // autodeposit off
+ chbook.AutoDeposit(0, common.Big0, balance)
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ exp = new(big.Int).SetUint64(40)
+ if chbook.balance.Cmp(exp) != 0 {
+ t.Fatalf("expected balance %v, got %v", exp, chbook.balance)
+ }
+
+ // autodeposit every 10ms if new cheque issued
+ interval := 30 * time.Millisecond
+ chbook.AutoDeposit(interval, common.Big1, balance)
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ exp = new(big.Int).SetUint64(38)
+ if chbook.balance.Cmp(exp) != 0 {
+ t.Fatalf("expected balance %v, got %v", exp, chbook.balance)
+ }
+
+ time.Sleep(3 * interval)
+ backend.Commit()
+ if chbook.balance.Cmp(balance) != 0 {
+ t.Fatalf("expected balance %v, got %v", balance, chbook.balance)
+ }
+
+ exp = new(big.Int).SetUint64(40)
+ chbook.AutoDeposit(4*interval, exp, balance)
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ time.Sleep(3 * interval)
+ backend.Commit()
+ if chbook.balance.Cmp(exp) != 0 {
+ t.Fatalf("expected balance %v, got %v", exp, chbook.balance)
+ }
+
+ _, err = chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ time.Sleep(1 * interval)
+ backend.Commit()
+
+ if chbook.balance.Cmp(balance) != 0 {
+ t.Fatalf("expected balance %v, got %v", balance, chbook.balance)
+ }
+
+ chbook.AutoDeposit(1*interval, common.Big0, balance)
+ chbook.Stop()
+
+ _, err = chbook.Issue(addr1, common.Big1)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ _, err = chbook.Issue(addr1, common.Big2)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ time.Sleep(1 * interval)
+ backend.Commit()
+
+ exp = new(big.Int).SetUint64(39)
+ if chbook.balance.Cmp(exp) != 0 {
+ t.Fatalf("expected balance %v, got %v", exp, chbook.balance)
+ }
+
+}
+
+func TestCash(t *testing.T) {
+ path := filepath.Join(os.TempDir(), "chequebook-test.json")
+ backend := newTestBackend()
+ contr0, err := deploy(key0, common.Big2, backend)
+ chbook, err := NewChequebook(path, contr0, key0, backend)
+ if err != nil {
+ t.Errorf("expected no error, got %v", err)
+ }
+ chbook.sent[addr1] = new(big.Int).SetUint64(42)
+ amount := common.Big1
+ chbook.balance = new(big.Int).Set(common.Big1)
+ ch, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ chbox, err := NewInbox(key1, contr0, addr1, &key0.PublicKey, backend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ // cashing latest cheque
+ _, err = chbox.Receive(ch)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ _, err = ch.Cash(chbook.session)
+ backend.Commit()
+
+ chbook.balance = new(big.Int).Set(common.Big3)
+ ch0, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ ch1, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ interval := 10 * time.Millisecond
+ // setting autocash with interval of 10ms
+ chbox.AutoCash(interval, nil)
+ _, err = chbox.Receive(ch0)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ _, err = chbox.Receive(ch1)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ // expBalance := big.NewInt(2)
+ // gotBalance := backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+ // after 3x interval time and 2 cheques received, exactly one cashing tx is sent
+ time.Sleep(4 * interval)
+ backend.Commit()
+
+ // expBalance = big.NewInt(4)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ // after stopping autocash no more tx are sent
+ ch2, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ chbox.Stop()
+ _, err = chbox.Receive(ch2)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ time.Sleep(2 * interval)
+ backend.Commit()
+ // expBalance = big.NewInt(4)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ // autocash below 1
+ chbook.balance = big.NewInt(2)
+ chbox.AutoCash(0, common.Big1)
+
+ ch3, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ // expBalance = big.NewInt(4)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ ch4, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ _, err = chbox.Receive(ch3)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ _, err = chbox.Receive(ch4)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+
+ // 2 checks of amount 1 received, exactly 1 tx is sent
+ // expBalance = big.NewInt(6)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ // autochash on receipt when maxUncashed is 0
+ chbook.balance = new(big.Int).Set(common.Big2)
+ chbox.AutoCash(0, common.Big0)
+
+ ch5, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ // expBalance = big.NewInt(5)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ ch6, err := chbook.Issue(addr1, amount)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+
+ _, err = chbox.Receive(ch5)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ // expBalance = big.NewInt(4)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+ _, err = chbox.Receive(ch6)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ backend.Commit()
+ // expBalance = big.NewInt(6)
+ // gotBalance = backend.BalanceAt(addr1)
+ // if gotBalance.Cmp(expBalance) != 0 {
+ // t.Fatalf("expected beneficiary balance %v, got %v", expBalance, gotBalance)
+ // }
+
+}
diff --git a/contracts/chequebook/contract/chequebook.go b/contracts/chequebook/contract/chequebook.go
new file mode 100644
index 000000000..47090152c
--- /dev/null
+++ b/contracts/chequebook/contract/chequebook.go
@@ -0,0 +1,541 @@
+// This file is an automatically generated Go binding. Do not modify as any
+// change will likely be lost upon the next re-generation!
+
+package contract
+
+import (
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ChequebookABI is the input ABI used to generate the binding from.
+const ChequebookABI = `[{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"sent","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"amount","type":"uint256"},{"name":"sig_v","type":"uint8"},{"name":"sig_r","type":"bytes32"},{"name":"sig_s","type":"bytes32"}],"name":"cash","outputs":[],"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"deadbeat","type":"address"}],"name":"Overdraft","type":"event"}]`
+
+// ChequebookBin is the compiled bytecode used for deploying new contracts.
+const ChequebookBin = `0x606060405260008054600160a060020a031916331790556101ff806100246000396000f3606060405260e060020a600035046341c0e1b581146100315780637bf786f814610059578063fbf788d614610071575b005b61002f60005433600160a060020a03908116911614156100bd57600054600160a060020a0316ff5b6100ab60043560016020526000908152604090205481565b61002f600435602435604435606435608435600160a060020a03851660009081526001602052604081205485116100bf575b505050505050565b60408051918252519081900360200190f35b565b50604080516c0100000000000000000000000030600160a060020a0390811682028352881602601482015260288101869052815190819003604801812080825260ff861660208381019190915282840186905260608301859052925190926001926080818101939182900301816000866161da5a03f11561000257505060405151600054600160a060020a0390811691161461015a576100a3565b600160a060020a038681166000908152600160205260409020543090911631908603106101b357604060008181208790559051600160a060020a0388169190819081818181818881f1935050505015156100a357610002565b60005460408051600160a060020a03929092168252517f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f9789181900360200190a185600160a060020a0316ff`
+
+// DeployChequebook deploys a new Ethereum contract, binding an instance of Chequebook to it.
+func DeployChequebook(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Chequebook, error) {
+ parsed, err := abi.JSON(strings.NewReader(ChequebookABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ChequebookBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}}, nil
+}
+
+// Chequebook is an auto generated Go binding around an Ethereum contract.
+type Chequebook struct {
+ ChequebookCaller // Read-only binding to the contract
+ ChequebookTransactor // Write-only binding to the contract
+}
+
+// ChequebookCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ChequebookCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ChequebookTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ChequebookTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ChequebookSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ChequebookSession struct {
+ Contract *Chequebook // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ChequebookCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ChequebookCallerSession struct {
+ Contract *ChequebookCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ChequebookTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ChequebookTransactorSession struct {
+ Contract *ChequebookTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ChequebookRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ChequebookRaw struct {
+ Contract *Chequebook // Generic contract binding to access the raw methods on
+}
+
+// ChequebookCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ChequebookCallerRaw struct {
+ Contract *ChequebookCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ChequebookTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ChequebookTransactorRaw struct {
+ Contract *ChequebookTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewChequebook creates a new instance of Chequebook, bound to a specific deployed contract.
+func NewChequebook(address common.Address, backend bind.ContractBackend) (*Chequebook, error) {
+ contract, err := bindChequebook(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Chequebook{ChequebookCaller: ChequebookCaller{contract: contract}, ChequebookTransactor: ChequebookTransactor{contract: contract}}, nil
+}
+
+// NewChequebookCaller creates a new read-only instance of Chequebook, bound to a specific deployed contract.
+func NewChequebookCaller(address common.Address, caller bind.ContractCaller) (*ChequebookCaller, error) {
+ contract, err := bindChequebook(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ChequebookCaller{contract: contract}, nil
+}
+
+// NewChequebookTransactor creates a new write-only instance of Chequebook, bound to a specific deployed contract.
+func NewChequebookTransactor(address common.Address, transactor bind.ContractTransactor) (*ChequebookTransactor, error) {
+ contract, err := bindChequebook(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &ChequebookTransactor{contract: contract}, nil
+}
+
+// bindChequebook binds a generic wrapper to an already deployed contract.
+func bindChequebook(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(ChequebookABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Chequebook *ChequebookRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Chequebook.Contract.ChequebookCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Chequebook *ChequebookRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chequebook.Contract.ChequebookTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Chequebook *ChequebookRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Chequebook.Contract.ChequebookTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Chequebook *ChequebookCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Chequebook.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Chequebook *ChequebookTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chequebook.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Chequebook *ChequebookTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Chequebook.Contract.contract.Transact(opts, method, params...)
+}
+
+// Sent is a free data retrieval call binding the contract method 0x7bf786f8.
+//
+// Solidity: function sent( address) constant returns(uint256)
+func (_Chequebook *ChequebookCaller) Sent(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) {
+ var (
+ ret0 = new(*big.Int)
+ )
+ out := ret0
+ err := _Chequebook.contract.Call(opts, out, "sent", arg0)
+ return *ret0, err
+}
+
+// Sent is a free data retrieval call binding the contract method 0x7bf786f8.
+//
+// Solidity: function sent( address) constant returns(uint256)
+func (_Chequebook *ChequebookSession) Sent(arg0 common.Address) (*big.Int, error) {
+ return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0)
+}
+
+// Sent is a free data retrieval call binding the contract method 0x7bf786f8.
+//
+// Solidity: function sent( address) constant returns(uint256)
+func (_Chequebook *ChequebookCallerSession) Sent(arg0 common.Address) (*big.Int, error) {
+ return _Chequebook.Contract.Sent(&_Chequebook.CallOpts, arg0)
+}
+
+// Cash is a paid mutator transaction binding the contract method 0xfbf788d6.
+//
+// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns()
+func (_Chequebook *ChequebookTransactor) Cash(opts *bind.TransactOpts, beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) {
+ return _Chequebook.contract.Transact(opts, "cash", beneficiary, amount, sig_v, sig_r, sig_s)
+}
+
+// Cash is a paid mutator transaction binding the contract method 0xfbf788d6.
+//
+// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns()
+func (_Chequebook *ChequebookSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) {
+ return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s)
+}
+
+// Cash is a paid mutator transaction binding the contract method 0xfbf788d6.
+//
+// Solidity: function cash(beneficiary address, amount uint256, sig_v uint8, sig_r bytes32, sig_s bytes32) returns()
+func (_Chequebook *ChequebookTransactorSession) Cash(beneficiary common.Address, amount *big.Int, sig_v uint8, sig_r [32]byte, sig_s [32]byte) (*types.Transaction, error) {
+ return _Chequebook.Contract.Cash(&_Chequebook.TransactOpts, beneficiary, amount, sig_v, sig_r, sig_s)
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Chequebook *ChequebookTransactor) Kill(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chequebook.contract.Transact(opts, "kill")
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Chequebook *ChequebookSession) Kill() (*types.Transaction, error) {
+ return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts)
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Chequebook *ChequebookTransactorSession) Kill() (*types.Transaction, error) {
+ return _Chequebook.Contract.Kill(&_Chequebook.TransactOpts)
+}
+
+// MortalABI is the input ABI used to generate the binding from.
+const MortalABI = `[{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"}]`
+
+// MortalBin is the compiled bytecode used for deploying new contracts.
+const MortalBin = `0x606060405260008054600160a060020a03191633179055605c8060226000396000f3606060405260e060020a600035046341c0e1b58114601a575b005b60186000543373ffffffffffffffffffffffffffffffffffffffff90811691161415605a5760005473ffffffffffffffffffffffffffffffffffffffff16ff5b56`
+
+// DeployMortal deploys a new Ethereum contract, binding an instance of Mortal to it.
+func DeployMortal(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Mortal, error) {
+ parsed, err := abi.JSON(strings.NewReader(MortalABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(MortalBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Mortal{MortalCaller: MortalCaller{contract: contract}, MortalTransactor: MortalTransactor{contract: contract}}, nil
+}
+
+// Mortal is an auto generated Go binding around an Ethereum contract.
+type Mortal struct {
+ MortalCaller // Read-only binding to the contract
+ MortalTransactor // Write-only binding to the contract
+}
+
+// MortalCaller is an auto generated read-only Go binding around an Ethereum contract.
+type MortalCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// MortalTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type MortalTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// MortalSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type MortalSession struct {
+ Contract *Mortal // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// MortalCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type MortalCallerSession struct {
+ Contract *MortalCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// MortalTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type MortalTransactorSession struct {
+ Contract *MortalTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// MortalRaw is an auto generated low-level Go binding around an Ethereum contract.
+type MortalRaw struct {
+ Contract *Mortal // Generic contract binding to access the raw methods on
+}
+
+// MortalCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type MortalCallerRaw struct {
+ Contract *MortalCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// MortalTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type MortalTransactorRaw struct {
+ Contract *MortalTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewMortal creates a new instance of Mortal, bound to a specific deployed contract.
+func NewMortal(address common.Address, backend bind.ContractBackend) (*Mortal, error) {
+ contract, err := bindMortal(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Mortal{MortalCaller: MortalCaller{contract: contract}, MortalTransactor: MortalTransactor{contract: contract}}, nil
+}
+
+// NewMortalCaller creates a new read-only instance of Mortal, bound to a specific deployed contract.
+func NewMortalCaller(address common.Address, caller bind.ContractCaller) (*MortalCaller, error) {
+ contract, err := bindMortal(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MortalCaller{contract: contract}, nil
+}
+
+// NewMortalTransactor creates a new write-only instance of Mortal, bound to a specific deployed contract.
+func NewMortalTransactor(address common.Address, transactor bind.ContractTransactor) (*MortalTransactor, error) {
+ contract, err := bindMortal(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &MortalTransactor{contract: contract}, nil
+}
+
+// bindMortal binds a generic wrapper to an already deployed contract.
+func bindMortal(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(MortalABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Mortal *MortalRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Mortal.Contract.MortalCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Mortal *MortalRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Mortal.Contract.MortalTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Mortal *MortalRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Mortal.Contract.MortalTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Mortal *MortalCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Mortal.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Mortal *MortalTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Mortal.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Mortal *MortalTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Mortal.Contract.contract.Transact(opts, method, params...)
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Mortal *MortalTransactor) Kill(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Mortal.contract.Transact(opts, "kill")
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Mortal *MortalSession) Kill() (*types.Transaction, error) {
+ return _Mortal.Contract.Kill(&_Mortal.TransactOpts)
+}
+
+// Kill is a paid mutator transaction binding the contract method 0x41c0e1b5.
+//
+// Solidity: function kill() returns()
+func (_Mortal *MortalTransactorSession) Kill() (*types.Transaction, error) {
+ return _Mortal.Contract.Kill(&_Mortal.TransactOpts)
+}
+
+// OwnedABI is the input ABI used to generate the binding from.
+const OwnedABI = `[{"inputs":[],"type":"constructor"}]`
+
+// OwnedBin is the compiled bytecode used for deploying new contracts.
+const OwnedBin = `0x606060405260008054600160a060020a0319163317905560068060226000396000f3606060405200`
+
+// DeployOwned deploys a new Ethereum contract, binding an instance of Owned to it.
+func DeployOwned(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Owned, error) {
+ parsed, err := abi.JSON(strings.NewReader(OwnedABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(OwnedBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Owned{OwnedCaller: OwnedCaller{contract: contract}, OwnedTransactor: OwnedTransactor{contract: contract}}, nil
+}
+
+// Owned is an auto generated Go binding around an Ethereum contract.
+type Owned struct {
+ OwnedCaller // Read-only binding to the contract
+ OwnedTransactor // Write-only binding to the contract
+}
+
+// OwnedCaller is an auto generated read-only Go binding around an Ethereum contract.
+type OwnedCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// OwnedTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type OwnedTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// OwnedSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type OwnedSession struct {
+ Contract *Owned // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// OwnedCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type OwnedCallerSession struct {
+ Contract *OwnedCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// OwnedTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type OwnedTransactorSession struct {
+ Contract *OwnedTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// OwnedRaw is an auto generated low-level Go binding around an Ethereum contract.
+type OwnedRaw struct {
+ Contract *Owned // Generic contract binding to access the raw methods on
+}
+
+// OwnedCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type OwnedCallerRaw struct {
+ Contract *OwnedCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// OwnedTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type OwnedTransactorRaw struct {
+ Contract *OwnedTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewOwned creates a new instance of Owned, bound to a specific deployed contract.
+func NewOwned(address common.Address, backend bind.ContractBackend) (*Owned, error) {
+ contract, err := bindOwned(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Owned{OwnedCaller: OwnedCaller{contract: contract}, OwnedTransactor: OwnedTransactor{contract: contract}}, nil
+}
+
+// NewOwnedCaller creates a new read-only instance of Owned, bound to a specific deployed contract.
+func NewOwnedCaller(address common.Address, caller bind.ContractCaller) (*OwnedCaller, error) {
+ contract, err := bindOwned(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OwnedCaller{contract: contract}, nil
+}
+
+// NewOwnedTransactor creates a new write-only instance of Owned, bound to a specific deployed contract.
+func NewOwnedTransactor(address common.Address, transactor bind.ContractTransactor) (*OwnedTransactor, error) {
+ contract, err := bindOwned(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &OwnedTransactor{contract: contract}, nil
+}
+
+// bindOwned binds a generic wrapper to an already deployed contract.
+func bindOwned(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(OwnedABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Owned *OwnedRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Owned.Contract.OwnedCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Owned *OwnedRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Owned.Contract.OwnedTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Owned *OwnedRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Owned.Contract.OwnedTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Owned *OwnedCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Owned.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Owned *OwnedTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Owned.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Owned *OwnedTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Owned.Contract.contract.Transact(opts, method, params...)
+}
diff --git a/contracts/chequebook/contract/chequebook.sol b/contracts/chequebook/contract/chequebook.sol
new file mode 100644
index 000000000..eefe6c063
--- /dev/null
+++ b/contracts/chequebook/contract/chequebook.sol
@@ -0,0 +1,45 @@
+import "mortal";
+
+/// @title Chequebook for Ethereum micropayments
+/// @author Daniel A. Nagy <daniel@ethdev.com>
+contract chequebook is mortal {
+ // Cumulative paid amount in wei to each beneficiary
+ mapping (address => uint256) public sent;
+
+ /// @notice Overdraft event
+ event Overdraft(address deadbeat);
+
+ /// @notice Cash cheque
+ ///
+ /// @param beneficiary beneficiary address
+ /// @param amount cumulative amount in wei
+ /// @param sig_v signature parameter v
+ /// @param sig_r signature parameter r
+ /// @param sig_s signature parameter s
+ /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount
+ function cash(address beneficiary, uint256 amount,
+ uint8 sig_v, bytes32 sig_r, bytes32 sig_s) {
+ // Check if the cheque is old.
+ // Only cheques that are more recent than the last cashed one are considered.
+ if(amount <= sent[beneficiary]) return;
+ // Check the digital signature of the cheque.
+ bytes32 hash = sha3(address(this), beneficiary, amount);
+ if(owner != ecrecover(hash, sig_v, sig_r, sig_s)) return;
+ // Attempt sending the difference between the cumulative amount on the cheque
+ // and the cumulative amount on the last cashed cheque to beneficiary.
+ if (amount - sent[beneficiary] >= this.balance) {
+ // update the cumulative amount before sending
+ sent[beneficiary] = amount;
+ if (!beneficiary.send(amount - sent[beneficiary])) {
+ // Upon failure to execute send, revert everything
+ throw;
+ }
+ } else {
+ // Upon failure, punish owner for writing a bounced cheque.
+ // owner.sendToDebtorsPrison();
+ Overdraft(owner);
+ // Compensate beneficiary.
+ suicide(beneficiary);
+ }
+ }
+}
diff --git a/contracts/chequebook/contract/code.go b/contracts/chequebook/contract/code.go
new file mode 100644
index 000000000..b08e04e71
--- /dev/null
+++ b/contracts/chequebook/contract/code.go
@@ -0,0 +1,5 @@
+package contract
+
+// ContractDeployedCode is used to detect suicides. This constant needs to be
+// updated when the contract code is changed.
+const ContractDeployedCode = "0x606060405260e060020a600035046341c0e1b581146100315780637bf786f814610059578063fbf788d614610071575b005b61002f60005433600160a060020a03908116911614156100bd57600054600160a060020a0316ff5b6100ab60043560016020526000908152604090205481565b61002f600435602435604435606435608435600160a060020a03851660009081526001602052604081205485116100bf575b505050505050565b60408051918252519081900360200190f35b565b50604080516c0100000000000000000000000030600160a060020a0390811682028352881602601482015260288101869052815190819003604801812080825260ff861660208381019190915282840186905260608301859052925190926001926080818101939182900301816000866161da5a03f11561000257505060405151600054600160a060020a0390811691161461015a576100a3565b600160a060020a038681166000908152600160205260409020543090911631908603106101b357604060008181208790559051600160a060020a0388169190819081818181818881f1935050505015156100a357610002565b60005460408051600160a060020a03929092168252517f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f9789181900360200190a185600160a060020a0316ff"
diff --git a/contracts/chequebook/gencode.go b/contracts/chequebook/gencode.go
new file mode 100644
index 000000000..faa927279
--- /dev/null
+++ b/contracts/chequebook/gencode.go
@@ -0,0 +1,71 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// +build none
+
+// This program generates contract/code.go, which contains the chequebook code
+// after deployment.
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/contracts/chequebook/contract"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+var (
+ testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ testAccount = core.GenesisAccount{
+ Address: crypto.PubkeyToAddress(testKey.PublicKey),
+ Balance: big.NewInt(500000000000),
+ }
+)
+
+func main() {
+ backend := backends.NewSimulatedBackend(testAccount)
+ auth := bind.NewKeyedTransactor(testKey)
+
+ // Deploy the contract, get the code.
+ addr, _, _, err := contract.DeployChequebook(auth, backend)
+ if err != nil {
+ panic(err)
+ }
+ backend.Commit()
+ code, err := backend.CodeAt(nil, addr, nil)
+ if err != nil {
+ panic(err)
+ }
+ if len(code) == 0 {
+ panic("empty code")
+ }
+
+ // Write the output file.
+ content := fmt.Sprintf(`package contract
+
+// ContractDeployedCode is used to detect suicides. This constant needs to be
+// updated when the contract code is changed.
+const ContractDeployedCode = "%#x"
+`, code)
+ if err := ioutil.WriteFile("contract/code.go", []byte(content), 0644); err != nil {
+ panic(err)
+ }
+}
diff --git a/contracts/ens/README.md b/contracts/ens/README.md
new file mode 100644
index 000000000..274fc14cd
--- /dev/null
+++ b/contracts/ens/README.md
@@ -0,0 +1,20 @@
+# Swarm ENS interface
+
+## Usage
+
+Full documentation for the Ethereum Name Service [can be found as EIP 137](https://github.com/ethereum/EIPs/issues/137).
+This package offers a simple binding that streamlines the registration arbitrary utf8 domain names to swarm content hashes.
+
+## Development
+
+The SOL file in contract subdirectory implements the ENS root registry, a simple
+first-in-first-served registrar for the root namespace, and a simple resolver contract;
+they're used in tests, and can be used to deploy these contracts for your own purposes.
+
+The solidity source code can be found at [github.com/arachnid/ens/](https://github.com/arachnid/ens/).
+
+The go bindings for ENS contracts are generated using `abigen` via the go generator:
+
+```shell
+go generate ./contracts/ens
+```
diff --git a/contracts/ens/contract/ens.go b/contracts/ens/contract/ens.go
new file mode 100644
index 000000000..aca16de50
--- /dev/null
+++ b/contracts/ens/contract/ens.go
@@ -0,0 +1,921 @@
+// This file is an automatically generated Go binding. Do not modify as any
+// change will likely be lost upon the next re-generation!
+
+package contract
+
+import (
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ENSABI is the input ABI used to generate the binding from.
+const ENSABI = `[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"label","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setOwner","outputs":[],"type":"function"},{"inputs":[{"name":"owner","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":true,"name":"label","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"resolver","type":"address"}],"name":"NewResolver","type":"event"}]`
+
+// ENSBin is the compiled bytecode used for deploying new contracts.
+const ENSBin = `0x606060405260405160208061032683395060806040525160008080526020527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb58054600160a060020a03191682179055506102c88061005e6000396000f3606060405260e060020a60003504630178b8bf811461004757806302571be31461006e57806306ab5923146100915780631896f70a146100c85780635b0fc9c3146100fc575b005b610130600435600081815260208190526040902060010154600160a060020a03165b919050565b610130600435600081815260208190526040902054600160a060020a0316610069565b6100456004356024356044356000838152602081905260408120548490600160a060020a0390811633919091161461014d57610002565b6100456004356024356000828152602081905260409020548290600160a060020a039081163391909116146101e757610002565b6100456004356024356000828152602081905260409020548290600160a060020a0390811633919091161461025957610002565b60408051600160a060020a03929092168252519081900360200190f35b60408051868152602081810187905282519182900383018220600160a060020a03871683529251929450869288927fce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e8292908290030190a382600060005060008460001916815260200190815260200160002060005060000160006101000a815481600160a060020a03021916908302179055505050505050565b60408051600160a060020a0384168152905184917f335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0919081900360200190a2506000828152602081905260409020600101805473ffffffffffffffffffffffffffffffffffffffff1916821790555050565b60408051600160a060020a0384168152905184917fd4735d920b0f87494915f556dd9b54c8f309026070caea5c737245152564d266919081900360200190a2506000828152602081905260409020805473ffffffffffffffffffffffffffffffffffffffff191682179055505056`
+
+// DeployENS deploys a new Ethereum contract, binding an instance of ENS to it.
+func DeployENS(auth *bind.TransactOpts, backend bind.ContractBackend, owner common.Address) (common.Address, *types.Transaction, *ENS, error) {
+ parsed, err := abi.JSON(strings.NewReader(ENSABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ENSBin), backend, owner)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ENS{ENSCaller: ENSCaller{contract: contract}, ENSTransactor: ENSTransactor{contract: contract}}, nil
+}
+
+// ENS is an auto generated Go binding around an Ethereum contract.
+type ENS struct {
+ ENSCaller // Read-only binding to the contract
+ ENSTransactor // Write-only binding to the contract
+}
+
+// ENSCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ENSCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ENSTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ENSTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ENSSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ENSSession struct {
+ Contract *ENS // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ENSCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ENSCallerSession struct {
+ Contract *ENSCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ENSTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ENSTransactorSession struct {
+ Contract *ENSTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ENSRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ENSRaw struct {
+ Contract *ENS // Generic contract binding to access the raw methods on
+}
+
+// ENSCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ENSCallerRaw struct {
+ Contract *ENSCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ENSTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ENSTransactorRaw struct {
+ Contract *ENSTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewENS creates a new instance of ENS, bound to a specific deployed contract.
+func NewENS(address common.Address, backend bind.ContractBackend) (*ENS, error) {
+ contract, err := bindENS(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ENS{ENSCaller: ENSCaller{contract: contract}, ENSTransactor: ENSTransactor{contract: contract}}, nil
+}
+
+// NewENSCaller creates a new read-only instance of ENS, bound to a specific deployed contract.
+func NewENSCaller(address common.Address, caller bind.ContractCaller) (*ENSCaller, error) {
+ contract, err := bindENS(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ENSCaller{contract: contract}, nil
+}
+
+// NewENSTransactor creates a new write-only instance of ENS, bound to a specific deployed contract.
+func NewENSTransactor(address common.Address, transactor bind.ContractTransactor) (*ENSTransactor, error) {
+ contract, err := bindENS(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &ENSTransactor{contract: contract}, nil
+}
+
+// bindENS binds a generic wrapper to an already deployed contract.
+func bindENS(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(ENSABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_ENS *ENSRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _ENS.Contract.ENSCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_ENS *ENSRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ENS.Contract.ENSTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_ENS *ENSRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ENS.Contract.ENSTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_ENS *ENSCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _ENS.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_ENS *ENSTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ENS.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_ENS *ENSTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ENS.Contract.contract.Transact(opts, method, params...)
+}
+
+// Owner is a free data retrieval call binding the contract method 0x02571be3.
+//
+// Solidity: function owner(node bytes32) constant returns(address)
+func (_ENS *ENSCaller) Owner(opts *bind.CallOpts, node [32]byte) (common.Address, error) {
+ var (
+ ret0 = new(common.Address)
+ )
+ out := ret0
+ err := _ENS.contract.Call(opts, out, "owner", node)
+ return *ret0, err
+}
+
+// Owner is a free data retrieval call binding the contract method 0x02571be3.
+//
+// Solidity: function owner(node bytes32) constant returns(address)
+func (_ENS *ENSSession) Owner(node [32]byte) (common.Address, error) {
+ return _ENS.Contract.Owner(&_ENS.CallOpts, node)
+}
+
+// Owner is a free data retrieval call binding the contract method 0x02571be3.
+//
+// Solidity: function owner(node bytes32) constant returns(address)
+func (_ENS *ENSCallerSession) Owner(node [32]byte) (common.Address, error) {
+ return _ENS.Contract.Owner(&_ENS.CallOpts, node)
+}
+
+// Resolver is a free data retrieval call binding the contract method 0x0178b8bf.
+//
+// Solidity: function resolver(node bytes32) constant returns(address)
+func (_ENS *ENSCaller) Resolver(opts *bind.CallOpts, node [32]byte) (common.Address, error) {
+ var (
+ ret0 = new(common.Address)
+ )
+ out := ret0
+ err := _ENS.contract.Call(opts, out, "resolver", node)
+ return *ret0, err
+}
+
+// Resolver is a free data retrieval call binding the contract method 0x0178b8bf.
+//
+// Solidity: function resolver(node bytes32) constant returns(address)
+func (_ENS *ENSSession) Resolver(node [32]byte) (common.Address, error) {
+ return _ENS.Contract.Resolver(&_ENS.CallOpts, node)
+}
+
+// Resolver is a free data retrieval call binding the contract method 0x0178b8bf.
+//
+// Solidity: function resolver(node bytes32) constant returns(address)
+func (_ENS *ENSCallerSession) Resolver(node [32]byte) (common.Address, error) {
+ return _ENS.Contract.Resolver(&_ENS.CallOpts, node)
+}
+
+// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3.
+//
+// Solidity: function setOwner(node bytes32, owner address) returns()
+func (_ENS *ENSTransactor) SetOwner(opts *bind.TransactOpts, node [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.contract.Transact(opts, "setOwner", node, owner)
+}
+
+// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3.
+//
+// Solidity: function setOwner(node bytes32, owner address) returns()
+func (_ENS *ENSSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner)
+}
+
+// SetOwner is a paid mutator transaction binding the contract method 0x5b0fc9c3.
+//
+// Solidity: function setOwner(node bytes32, owner address) returns()
+func (_ENS *ENSTransactorSession) SetOwner(node [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetOwner(&_ENS.TransactOpts, node, owner)
+}
+
+// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a.
+//
+// Solidity: function setResolver(node bytes32, resolver address) returns()
+func (_ENS *ENSTransactor) SetResolver(opts *bind.TransactOpts, node [32]byte, resolver common.Address) (*types.Transaction, error) {
+ return _ENS.contract.Transact(opts, "setResolver", node, resolver)
+}
+
+// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a.
+//
+// Solidity: function setResolver(node bytes32, resolver address) returns()
+func (_ENS *ENSSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver)
+}
+
+// SetResolver is a paid mutator transaction binding the contract method 0x1896f70a.
+//
+// Solidity: function setResolver(node bytes32, resolver address) returns()
+func (_ENS *ENSTransactorSession) SetResolver(node [32]byte, resolver common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetResolver(&_ENS.TransactOpts, node, resolver)
+}
+
+// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923.
+//
+// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns()
+func (_ENS *ENSTransactor) SetSubnodeOwner(opts *bind.TransactOpts, node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.contract.Transact(opts, "setSubnodeOwner", node, label, owner)
+}
+
+// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923.
+//
+// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns()
+func (_ENS *ENSSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner)
+}
+
+// SetSubnodeOwner is a paid mutator transaction binding the contract method 0x06ab5923.
+//
+// Solidity: function setSubnodeOwner(node bytes32, label bytes32, owner address) returns()
+func (_ENS *ENSTransactorSession) SetSubnodeOwner(node [32]byte, label [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _ENS.Contract.SetSubnodeOwner(&_ENS.TransactOpts, node, label, owner)
+}
+
+// FIFSRegistrarABI is the input ABI used to generate the binding from.
+const FIFSRegistrarABI = `[{"constant":false,"inputs":[{"name":"subnode","type":"bytes32"},{"name":"owner","type":"address"}],"name":"register","outputs":[],"type":"function"},{"inputs":[{"name":"ensAddr","type":"address"},{"name":"node","type":"bytes32"}],"type":"constructor"}]`
+
+// FIFSRegistrarBin is the compiled bytecode used for deploying new contracts.
+const FIFSRegistrarBin = `0x6060604081815280610620833960a090525160805160008054600160a060020a031916831790558160a0610367806100878339018082600160a060020a03168152602001915050604051809103906000f0600160006101000a815481600160a060020a0302191690830217905550806002600050819055505050610232806103ee6000396000f3606060405260405160208061036783395060806040525160008054600160a060020a0319168217905550610330806100376000396000f36060604052361561004b5760e060020a60003504632dff694181146100535780633b3b57de1461007557806341b9dc2b146100a0578063c3d014d614610139578063d5fa2b00146101b2575b61022b610002565b61022d6004356000818152600260205260408120549081141561027057610002565b61023f600435600081815260016020526040812054600160a060020a03169081141561027057610002565b61025c60043560243560007f6164647200000000000000000000000000000000000000000000000000000000821480156100f05750600083815260016020526040812054600160a060020a031614155b8061013257507f636f6e74656e740000000000000000000000000000000000000000000000000082148015610132575060008381526002602052604081205414155b9392505050565b61022b600435602435600080546040805160e060020a6302571be30281526004810186905290518593600160a060020a033381169416926302571be392602482810193602093839003909101908290876161da5a03f11561000257505060405151600160a060020a031691909114905061027557610002565b61022b600435602435600080546040805160e060020a6302571be30281526004810186905290518593600160a060020a033381169416926302571be392602482810193602093839003909101908290876161da5a03f11561000257505060405151600160a060020a03169190911490506102c157610002565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b919050565b6000838152600260209081526040918290208490558151848152915185927f0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc92908290030190a2505050565b600083815260016020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916851790558151600160a060020a0385168152915185927f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd292908290030190a250505056606060405260e060020a6000350463d22057a9811461001b575b005b61001960043560243560025460408051918252602082810185905260008054835194859003840185207f02571be300000000000000000000000000000000000000000000000000000000865260048601819052935193949193600160a060020a03909116926302571be39260248181019391829003018187876161da5a03f11561000257505060405151915050600160a060020a0381166000148015906100d4575033600160a060020a031681600160a060020a031614155b156100de57610002565b60408051600080546002547f06ab592300000000000000000000000000000000000000000000000000000000845260048401526024830188905230600160a060020a03908116604485015293519316926306ab5923926064818101939291829003018183876161da5a03f11561000257505060008054600154604080517f1896f70a00000000000000000000000000000000000000000000000000000000815260048101889052600160a060020a0392831660248201529051929091169350631896f70a926044828101939192829003018183876161da5a03f11561000257505060008054604080517f5b0fc9c300000000000000000000000000000000000000000000000000000000815260048101879052600160a060020a0388811660248301529151929091169350635b0fc9c3926044828101939192829003018183876161da5a03f115610002575050505050505056`
+
+// DeployFIFSRegistrar deploys a new Ethereum contract, binding an instance of FIFSRegistrar to it.
+func DeployFIFSRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address, node [32]byte) (common.Address, *types.Transaction, *FIFSRegistrar, error) {
+ parsed, err := abi.JSON(strings.NewReader(FIFSRegistrarABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(FIFSRegistrarBin), backend, ensAddr, node)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &FIFSRegistrar{FIFSRegistrarCaller: FIFSRegistrarCaller{contract: contract}, FIFSRegistrarTransactor: FIFSRegistrarTransactor{contract: contract}}, nil
+}
+
+// FIFSRegistrar is an auto generated Go binding around an Ethereum contract.
+type FIFSRegistrar struct {
+ FIFSRegistrarCaller // Read-only binding to the contract
+ FIFSRegistrarTransactor // Write-only binding to the contract
+}
+
+// FIFSRegistrarCaller is an auto generated read-only Go binding around an Ethereum contract.
+type FIFSRegistrarCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// FIFSRegistrarTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type FIFSRegistrarTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// FIFSRegistrarSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type FIFSRegistrarSession struct {
+ Contract *FIFSRegistrar // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// FIFSRegistrarCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type FIFSRegistrarCallerSession struct {
+ Contract *FIFSRegistrarCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// FIFSRegistrarTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type FIFSRegistrarTransactorSession struct {
+ Contract *FIFSRegistrarTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// FIFSRegistrarRaw is an auto generated low-level Go binding around an Ethereum contract.
+type FIFSRegistrarRaw struct {
+ Contract *FIFSRegistrar // Generic contract binding to access the raw methods on
+}
+
+// FIFSRegistrarCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type FIFSRegistrarCallerRaw struct {
+ Contract *FIFSRegistrarCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// FIFSRegistrarTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type FIFSRegistrarTransactorRaw struct {
+ Contract *FIFSRegistrarTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewFIFSRegistrar creates a new instance of FIFSRegistrar, bound to a specific deployed contract.
+func NewFIFSRegistrar(address common.Address, backend bind.ContractBackend) (*FIFSRegistrar, error) {
+ contract, err := bindFIFSRegistrar(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &FIFSRegistrar{FIFSRegistrarCaller: FIFSRegistrarCaller{contract: contract}, FIFSRegistrarTransactor: FIFSRegistrarTransactor{contract: contract}}, nil
+}
+
+// NewFIFSRegistrarCaller creates a new read-only instance of FIFSRegistrar, bound to a specific deployed contract.
+func NewFIFSRegistrarCaller(address common.Address, caller bind.ContractCaller) (*FIFSRegistrarCaller, error) {
+ contract, err := bindFIFSRegistrar(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &FIFSRegistrarCaller{contract: contract}, nil
+}
+
+// NewFIFSRegistrarTransactor creates a new write-only instance of FIFSRegistrar, bound to a specific deployed contract.
+func NewFIFSRegistrarTransactor(address common.Address, transactor bind.ContractTransactor) (*FIFSRegistrarTransactor, error) {
+ contract, err := bindFIFSRegistrar(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &FIFSRegistrarTransactor{contract: contract}, nil
+}
+
+// bindFIFSRegistrar binds a generic wrapper to an already deployed contract.
+func bindFIFSRegistrar(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(FIFSRegistrarABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_FIFSRegistrar *FIFSRegistrarRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _FIFSRegistrar.Contract.FIFSRegistrarCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_FIFSRegistrar *FIFSRegistrarRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.FIFSRegistrarTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_FIFSRegistrar *FIFSRegistrarRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.FIFSRegistrarTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_FIFSRegistrar *FIFSRegistrarCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _FIFSRegistrar.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_FIFSRegistrar *FIFSRegistrarTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_FIFSRegistrar *FIFSRegistrarTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.contract.Transact(opts, method, params...)
+}
+
+// Register is a paid mutator transaction binding the contract method 0xd22057a9.
+//
+// Solidity: function register(subnode bytes32, owner address) returns()
+func (_FIFSRegistrar *FIFSRegistrarTransactor) Register(opts *bind.TransactOpts, subnode [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _FIFSRegistrar.contract.Transact(opts, "register", subnode, owner)
+}
+
+// Register is a paid mutator transaction binding the contract method 0xd22057a9.
+//
+// Solidity: function register(subnode bytes32, owner address) returns()
+func (_FIFSRegistrar *FIFSRegistrarSession) Register(subnode [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, subnode, owner)
+}
+
+// Register is a paid mutator transaction binding the contract method 0xd22057a9.
+//
+// Solidity: function register(subnode bytes32, owner address) returns()
+func (_FIFSRegistrar *FIFSRegistrarTransactorSession) Register(subnode [32]byte, owner common.Address) (*types.Transaction, error) {
+ return _FIFSRegistrar.Contract.Register(&_FIFSRegistrar.TransactOpts, subnode, owner)
+}
+
+// PublicResolverABI is the input ABI used to generate the binding from.
+const PublicResolverABI = `[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"content","outputs":[{"name":"ret","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"addr","outputs":[{"name":"ret","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"kind","type":"bytes32"}],"name":"has","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"hash","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"addr","type":"address"}],"name":"setAddr","outputs":[],"type":"function"},{"inputs":[{"name":"ensAddr","type":"address"}],"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"hash","type":"bytes32"}],"name":"ContentChanged","type":"event"}]`
+
+// PublicResolverBin is the compiled bytecode used for deploying new contracts.
+const PublicResolverBin = `0x606060405260405160208061036783395060806040525160008054600160a060020a0319168217905550610330806100376000396000f36060604052361561004b5760e060020a60003504632dff694181146100535780633b3b57de1461007557806341b9dc2b146100a0578063c3d014d614610139578063d5fa2b00146101b2575b61022b610002565b61022d6004356000818152600260205260408120549081141561027057610002565b61023f600435600081815260016020526040812054600160a060020a03169081141561027057610002565b61025c60043560243560007f6164647200000000000000000000000000000000000000000000000000000000821480156100f05750600083815260016020526040812054600160a060020a031614155b8061013257507f636f6e74656e740000000000000000000000000000000000000000000000000082148015610132575060008381526002602052604081205414155b9392505050565b61022b600435602435600080546040805160e060020a6302571be30281526004810186905290518593600160a060020a033381169416926302571be392602482810193602093839003909101908290876161da5a03f11561000257505060405151600160a060020a031691909114905061027557610002565b61022b600435602435600080546040805160e060020a6302571be30281526004810186905290518593600160a060020a033381169416926302571be392602482810193602093839003909101908290876161da5a03f11561000257505060405151600160a060020a03169190911490506102c157610002565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b604080519115158252519081900360200190f35b919050565b6000838152600260209081526040918290208490558151848152915185927f0424b6fe0d9c3bdbece0e7879dc241bb0c22e900be8b6c168b4ee08bd9bf83bc92908290030190a2505050565b600083815260016020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff1916851790558151600160a060020a0385168152915185927f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd292908290030190a250505056`
+
+// DeployPublicResolver deploys a new Ethereum contract, binding an instance of PublicResolver to it.
+func DeployPublicResolver(auth *bind.TransactOpts, backend bind.ContractBackend, ensAddr common.Address) (common.Address, *types.Transaction, *PublicResolver, error) {
+ parsed, err := abi.JSON(strings.NewReader(PublicResolverABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PublicResolverBin), backend, ensAddr)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}}, nil
+}
+
+// PublicResolver is an auto generated Go binding around an Ethereum contract.
+type PublicResolver struct {
+ PublicResolverCaller // Read-only binding to the contract
+ PublicResolverTransactor // Write-only binding to the contract
+}
+
+// PublicResolverCaller is an auto generated read-only Go binding around an Ethereum contract.
+type PublicResolverCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// PublicResolverTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type PublicResolverTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// PublicResolverSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type PublicResolverSession struct {
+ Contract *PublicResolver // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// PublicResolverCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type PublicResolverCallerSession struct {
+ Contract *PublicResolverCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// PublicResolverTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type PublicResolverTransactorSession struct {
+ Contract *PublicResolverTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// PublicResolverRaw is an auto generated low-level Go binding around an Ethereum contract.
+type PublicResolverRaw struct {
+ Contract *PublicResolver // Generic contract binding to access the raw methods on
+}
+
+// PublicResolverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type PublicResolverCallerRaw struct {
+ Contract *PublicResolverCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// PublicResolverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type PublicResolverTransactorRaw struct {
+ Contract *PublicResolverTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewPublicResolver creates a new instance of PublicResolver, bound to a specific deployed contract.
+func NewPublicResolver(address common.Address, backend bind.ContractBackend) (*PublicResolver, error) {
+ contract, err := bindPublicResolver(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &PublicResolver{PublicResolverCaller: PublicResolverCaller{contract: contract}, PublicResolverTransactor: PublicResolverTransactor{contract: contract}}, nil
+}
+
+// NewPublicResolverCaller creates a new read-only instance of PublicResolver, bound to a specific deployed contract.
+func NewPublicResolverCaller(address common.Address, caller bind.ContractCaller) (*PublicResolverCaller, error) {
+ contract, err := bindPublicResolver(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PublicResolverCaller{contract: contract}, nil
+}
+
+// NewPublicResolverTransactor creates a new write-only instance of PublicResolver, bound to a specific deployed contract.
+func NewPublicResolverTransactor(address common.Address, transactor bind.ContractTransactor) (*PublicResolverTransactor, error) {
+ contract, err := bindPublicResolver(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &PublicResolverTransactor{contract: contract}, nil
+}
+
+// bindPublicResolver binds a generic wrapper to an already deployed contract.
+func bindPublicResolver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(PublicResolverABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_PublicResolver *PublicResolverRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _PublicResolver.Contract.PublicResolverCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_PublicResolver *PublicResolverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PublicResolver.Contract.PublicResolverTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_PublicResolver *PublicResolverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PublicResolver.Contract.PublicResolverTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_PublicResolver *PublicResolverCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _PublicResolver.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_PublicResolver *PublicResolverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PublicResolver.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_PublicResolver *PublicResolverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PublicResolver.Contract.contract.Transact(opts, method, params...)
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_PublicResolver *PublicResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) {
+ var (
+ ret0 = new(common.Address)
+ )
+ out := ret0
+ err := _PublicResolver.contract.Call(opts, out, "addr", node)
+ return *ret0, err
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_PublicResolver *PublicResolverSession) Addr(node [32]byte) (common.Address, error) {
+ return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node)
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_PublicResolver *PublicResolverCallerSession) Addr(node [32]byte) (common.Address, error) {
+ return _PublicResolver.Contract.Addr(&_PublicResolver.CallOpts, node)
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_PublicResolver *PublicResolverCaller) Content(opts *bind.CallOpts, node [32]byte) ([32]byte, error) {
+ var (
+ ret0 = new([32]byte)
+ )
+ out := ret0
+ err := _PublicResolver.contract.Call(opts, out, "content", node)
+ return *ret0, err
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_PublicResolver *PublicResolverSession) Content(node [32]byte) ([32]byte, error) {
+ return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node)
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_PublicResolver *PublicResolverCallerSession) Content(node [32]byte) ([32]byte, error) {
+ return _PublicResolver.Contract.Content(&_PublicResolver.CallOpts, node)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_PublicResolver *PublicResolverTransactor) Has(opts *bind.TransactOpts, node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.contract.Transact(opts, "has", node, kind)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_PublicResolver *PublicResolverSession) Has(node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.Contract.Has(&_PublicResolver.TransactOpts, node, kind)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_PublicResolver *PublicResolverTransactorSession) Has(node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.Contract.Has(&_PublicResolver.TransactOpts, node, kind)
+}
+
+// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00.
+//
+// Solidity: function setAddr(node bytes32, addr address) returns()
+func (_PublicResolver *PublicResolverTransactor) SetAddr(opts *bind.TransactOpts, node [32]byte, addr common.Address) (*types.Transaction, error) {
+ return _PublicResolver.contract.Transact(opts, "setAddr", node, addr)
+}
+
+// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00.
+//
+// Solidity: function setAddr(node bytes32, addr address) returns()
+func (_PublicResolver *PublicResolverSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) {
+ return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr)
+}
+
+// SetAddr is a paid mutator transaction binding the contract method 0xd5fa2b00.
+//
+// Solidity: function setAddr(node bytes32, addr address) returns()
+func (_PublicResolver *PublicResolverTransactorSession) SetAddr(node [32]byte, addr common.Address) (*types.Transaction, error) {
+ return _PublicResolver.Contract.SetAddr(&_PublicResolver.TransactOpts, node, addr)
+}
+
+// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6.
+//
+// Solidity: function setContent(node bytes32, hash bytes32) returns()
+func (_PublicResolver *PublicResolverTransactor) SetContent(opts *bind.TransactOpts, node [32]byte, hash [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.contract.Transact(opts, "setContent", node, hash)
+}
+
+// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6.
+//
+// Solidity: function setContent(node bytes32, hash bytes32) returns()
+func (_PublicResolver *PublicResolverSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash)
+}
+
+// SetContent is a paid mutator transaction binding the contract method 0xc3d014d6.
+//
+// Solidity: function setContent(node bytes32, hash bytes32) returns()
+func (_PublicResolver *PublicResolverTransactorSession) SetContent(node [32]byte, hash [32]byte) (*types.Transaction, error) {
+ return _PublicResolver.Contract.SetContent(&_PublicResolver.TransactOpts, node, hash)
+}
+
+// ResolverABI is the input ABI used to generate the binding from.
+const ResolverABI = `[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"content","outputs":[{"name":"ret","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"addr","outputs":[{"name":"ret","type":"address"}],"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"kind","type":"bytes32"}],"name":"has","outputs":[{"name":"","type":"bool"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"hash","type":"bytes32"}],"name":"ContentChanged","type":"event"}]`
+
+// ResolverBin is the compiled bytecode used for deploying new contracts.
+const ResolverBin = `0x`
+
+// DeployResolver deploys a new Ethereum contract, binding an instance of Resolver to it.
+func DeployResolver(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Resolver, error) {
+ parsed, err := abi.JSON(strings.NewReader(ResolverABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ResolverBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Resolver{ResolverCaller: ResolverCaller{contract: contract}, ResolverTransactor: ResolverTransactor{contract: contract}}, nil
+}
+
+// Resolver is an auto generated Go binding around an Ethereum contract.
+type Resolver struct {
+ ResolverCaller // Read-only binding to the contract
+ ResolverTransactor // Write-only binding to the contract
+}
+
+// ResolverCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ResolverCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ResolverTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ResolverTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ResolverSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ResolverSession struct {
+ Contract *Resolver // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ResolverCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ResolverCallerSession struct {
+ Contract *ResolverCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ResolverTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ResolverTransactorSession struct {
+ Contract *ResolverTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ResolverRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ResolverRaw struct {
+ Contract *Resolver // Generic contract binding to access the raw methods on
+}
+
+// ResolverCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ResolverCallerRaw struct {
+ Contract *ResolverCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ResolverTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ResolverTransactorRaw struct {
+ Contract *ResolverTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewResolver creates a new instance of Resolver, bound to a specific deployed contract.
+func NewResolver(address common.Address, backend bind.ContractBackend) (*Resolver, error) {
+ contract, err := bindResolver(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Resolver{ResolverCaller: ResolverCaller{contract: contract}, ResolverTransactor: ResolverTransactor{contract: contract}}, nil
+}
+
+// NewResolverCaller creates a new read-only instance of Resolver, bound to a specific deployed contract.
+func NewResolverCaller(address common.Address, caller bind.ContractCaller) (*ResolverCaller, error) {
+ contract, err := bindResolver(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ResolverCaller{contract: contract}, nil
+}
+
+// NewResolverTransactor creates a new write-only instance of Resolver, bound to a specific deployed contract.
+func NewResolverTransactor(address common.Address, transactor bind.ContractTransactor) (*ResolverTransactor, error) {
+ contract, err := bindResolver(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &ResolverTransactor{contract: contract}, nil
+}
+
+// bindResolver binds a generic wrapper to an already deployed contract.
+func bindResolver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(ResolverABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Resolver *ResolverRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Resolver.Contract.ResolverCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Resolver *ResolverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Resolver.Contract.ResolverTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Resolver *ResolverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Resolver.Contract.ResolverTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Resolver *ResolverCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _Resolver.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Resolver *ResolverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Resolver.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Resolver *ResolverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Resolver.Contract.contract.Transact(opts, method, params...)
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_Resolver *ResolverCaller) Addr(opts *bind.CallOpts, node [32]byte) (common.Address, error) {
+ var (
+ ret0 = new(common.Address)
+ )
+ out := ret0
+ err := _Resolver.contract.Call(opts, out, "addr", node)
+ return *ret0, err
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_Resolver *ResolverSession) Addr(node [32]byte) (common.Address, error) {
+ return _Resolver.Contract.Addr(&_Resolver.CallOpts, node)
+}
+
+// Addr is a free data retrieval call binding the contract method 0x3b3b57de.
+//
+// Solidity: function addr(node bytes32) constant returns(ret address)
+func (_Resolver *ResolverCallerSession) Addr(node [32]byte) (common.Address, error) {
+ return _Resolver.Contract.Addr(&_Resolver.CallOpts, node)
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_Resolver *ResolverCaller) Content(opts *bind.CallOpts, node [32]byte) ([32]byte, error) {
+ var (
+ ret0 = new([32]byte)
+ )
+ out := ret0
+ err := _Resolver.contract.Call(opts, out, "content", node)
+ return *ret0, err
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_Resolver *ResolverSession) Content(node [32]byte) ([32]byte, error) {
+ return _Resolver.Contract.Content(&_Resolver.CallOpts, node)
+}
+
+// Content is a free data retrieval call binding the contract method 0x2dff6941.
+//
+// Solidity: function content(node bytes32) constant returns(ret bytes32)
+func (_Resolver *ResolverCallerSession) Content(node [32]byte) ([32]byte, error) {
+ return _Resolver.Contract.Content(&_Resolver.CallOpts, node)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_Resolver *ResolverTransactor) Has(opts *bind.TransactOpts, node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _Resolver.contract.Transact(opts, "has", node, kind)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_Resolver *ResolverSession) Has(node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _Resolver.Contract.Has(&_Resolver.TransactOpts, node, kind)
+}
+
+// Has is a paid mutator transaction binding the contract method 0x41b9dc2b.
+//
+// Solidity: function has(node bytes32, kind bytes32) returns(bool)
+func (_Resolver *ResolverTransactorSession) Has(node [32]byte, kind [32]byte) (*types.Transaction, error) {
+ return _Resolver.Contract.Has(&_Resolver.TransactOpts, node, kind)
+}
diff --git a/contracts/ens/contract/ens.sol b/contracts/ens/contract/ens.sol
new file mode 100644
index 000000000..114cd7319
--- /dev/null
+++ b/contracts/ens/contract/ens.sol
@@ -0,0 +1,226 @@
+// Ethereum Name Service contracts by Nick Johnson <nick@ethereum.org>
+//
+// To the extent possible under law, the person who associated CC0 with
+// ENS contracts has waived all copyright and related or neighboring rights
+// to ENS.
+//
+// You should have received a copy of the CC0 legalcode along with this
+// work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+
+/**
+ * The ENS registry contract.
+ */
+contract ENS {
+ struct Record {
+ address owner;
+ address resolver;
+ }
+
+ mapping(bytes32=>Record) records;
+
+ // Logged when the owner of a node assigns a new owner to a subnode.
+ event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
+
+ // Logged when the owner of a node transfers ownership to a new account.
+ event Transfer(bytes32 indexed node, address owner);
+
+ // Logged when the owner of a node changes the resolver for that node.
+ event NewResolver(bytes32 indexed node, address resolver);
+
+ // Permits modifications only by the owner of the specified node.
+ modifier only_owner(bytes32 node) {
+ if(records[node].owner != msg.sender) throw;
+ _
+ }
+
+ /**
+ * Constructs a new ENS registrar, with the provided address as the owner of the root node.
+ */
+ function ENS(address owner) {
+ records[0].owner = owner;
+ }
+
+ /**
+ * Returns the address that owns the specified node.
+ */
+ function owner(bytes32 node) constant returns (address) {
+ return records[node].owner;
+ }
+
+ /**
+ * Returns the address of the resolver for the specified node.
+ */
+ function resolver(bytes32 node) constant returns (address) {
+ return records[node].resolver;
+ }
+
+ /**
+ * Transfers ownership of a node to a new address. May only be called by the current
+ * owner of the node.
+ * @param node The node to transfer ownership of.
+ * @param owner The address of the new owner.
+ */
+ function setOwner(bytes32 node, address owner) only_owner(node) {
+ Transfer(node, owner);
+ records[node].owner = owner;
+ }
+
+ /**
+ * Transfers ownership of a subnode sha3(node, label) to a new address. May only be
+ * called by the owner of the parent node.
+ * @param node The parent node.
+ * @param label The hash of the label specifying the subnode.
+ * @param owner The address of the new owner.
+ */
+ function setSubnodeOwner(bytes32 node, bytes32 label, address owner) only_owner(node) {
+ var subnode = sha3(node, label);
+ NewOwner(node, label, owner);
+ records[subnode].owner = owner;
+ }
+
+ /**
+ * Sets the resolver address for the specified node.
+ * @param node The node to update.
+ * @param resolver The address of the resolver.
+ */
+ function setResolver(bytes32 node, address resolver) only_owner(node) {
+ NewResolver(node, resolver);
+ records[node].resolver = resolver;
+ }
+}
+
+/**
+ * A registrar that allocates subdomains to the first person to claim them. It also deploys
+ * a simple resolver contract and sets that as the default resolver on new names for
+ * convenience.
+ */
+contract FIFSRegistrar {
+ ENS ens;
+ PublicResolver defaultResolver;
+ bytes32 rootNode;
+
+ /**
+ * Constructor.
+ * @param ensAddr The address of the ENS registry.
+ * @param node The node that this registrar administers.
+ */
+ function FIFSRegistrar(address ensAddr, bytes32 node) {
+ ens = ENS(ensAddr);
+ defaultResolver = new PublicResolver(ensAddr);
+ rootNode = node;
+ }
+
+ /**
+ * Register a name, or change the owner of an existing registration.
+ * @param subnode The hash of the label to register.
+ * @param owner The address of the new owner.
+ */
+ function register(bytes32 subnode, address owner) {
+ var node = sha3(rootNode, subnode);
+ var currentOwner = ens.owner(node);
+ if(currentOwner != 0 && currentOwner != msg.sender)
+ throw;
+
+ // Temporarily set ourselves as the owner
+ ens.setSubnodeOwner(rootNode, subnode, this);
+ // Set up the default resolver
+ ens.setResolver(node, defaultResolver);
+ // Set the owner to the real owner
+ ens.setOwner(node, owner);
+ }
+}
+
+contract Resolver {
+ event AddrChanged(bytes32 indexed node, address a);
+ event ContentChanged(bytes32 indexed node, bytes32 hash);
+
+ function has(bytes32 node, bytes32 kind) returns (bool);
+ function addr(bytes32 node) constant returns (address ret);
+ function content(bytes32 node) constant returns (bytes32 ret);
+}
+
+/**
+ * A simple resolver anyone can use; only allows the owner of a node to set its
+ * address.
+ */
+contract PublicResolver is Resolver {
+ ENS ens;
+ mapping(bytes32=>address) addresses;
+ mapping(bytes32=>bytes32) contents;
+
+ modifier only_owner(bytes32 node) {
+ if(ens.owner(node) != msg.sender) throw;
+ _
+ }
+
+ /**
+ * Constructor.
+ * @param ensAddr The ENS registrar contract.
+ */
+ function PublicResolver(address ensAddr) {
+ ens = ENS(ensAddr);
+ }
+
+ /**
+ * Fallback function.
+ */
+ function() {
+ throw;
+ }
+
+ /**
+ * Returns true if the specified node has the specified record type.
+ * @param node The ENS node to query.
+ * @param kind The record type name, as specified in EIP137.
+ * @return True if this resolver has a record of the provided type on the
+ * provided node.
+ */
+ function has(bytes32 node, bytes32 kind) returns (bool) {
+ return (kind == "addr" && addresses[node] != 0) ||
+ (kind == "content" && contents[node] != 0);
+ }
+
+ /**
+ * Returns the address associated with an ENS node.
+ * @param node The ENS node to query.
+ * @return The associated address.
+ */
+ function addr(bytes32 node) constant returns (address ret) {
+ ret = addresses[node];
+ if(ret == 0)
+ throw;
+ }
+
+ /**
+ * Returns the content hash associated with an ENS node.
+ * @param node The ENS node to query.
+ * @return The associated content hash.
+ */
+ function content(bytes32 node) constant returns (bytes32 ret) {
+ ret = contents[node];
+ if(ret == 0)
+ throw;
+ }
+
+ /**
+ * Sets the address associated with an ENS node.
+ * May only be called by the owner of that node in the ENS registry.
+ * @param node The node to update.
+ * @param addr The address to set.
+ */
+ function setAddr(bytes32 node, address addr) only_owner(node) {
+ addresses[node] = addr;
+ AddrChanged(node, addr);
+ }
+
+ /**
+ * Sets the content hash associated with an ENS node.
+ * May only be called by the owner of that node in the ENS registry.
+ * @param node The node to update.
+ * @param hash The content hash to set.
+ */
+ function setContent(bytes32 node, bytes32 hash) only_owner(node) {
+ contents[node] = hash;
+ ContentChanged(node, hash);
+ }
+}
diff --git a/contracts/ens/ens.go b/contracts/ens/ens.go
new file mode 100644
index 000000000..7806742cf
--- /dev/null
+++ b/contracts/ens/ens.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ens
+
+//go:generate abigen --sol contract/ens.sol --pkg contract --out contract/ens.go
+
+import (
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/contracts/ens/contract"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// swarm domain name registry and resolver
+type ENS struct {
+ *contract.ENSSession
+ contractBackend bind.ContractBackend
+}
+
+// NewENS creates a struct exposing convenient high-level operations for interacting with
+// the Ethereum Name Service.
+func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*ENS, error) {
+ ens, err := contract.NewENS(contractAddr, contractBackend)
+ if err != nil {
+ return nil, err
+ }
+
+ return &ENS{
+ &contract.ENSSession{
+ Contract: ens,
+ TransactOpts: *transactOpts,
+ },
+ contractBackend,
+ }, nil
+}
+
+// DeployENS deploys an instance of the ENS nameservice, with a 'first in first served' root registrar.
+func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (*ENS, error) {
+ // Deploy the ENS registry
+ ensAddr, _, _, err := contract.DeployENS(transactOpts, contractBackend, transactOpts.From)
+ if err != nil {
+ return nil, err
+ }
+
+ ens, err := NewENS(transactOpts, ensAddr, contractBackend)
+ if err != nil {
+ return nil, err
+ }
+
+ // Deploy the registrar
+ regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{})
+ if err != nil {
+ return nil, err
+ }
+
+ // Set the registrar as owner of the ENS root
+ _, err = ens.SetOwner([32]byte{}, regAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ return ens, nil
+}
+
+func ensParentNode(name string) (common.Hash, common.Hash) {
+ parts := strings.SplitN(name, ".", 2)
+ label := crypto.Keccak256Hash([]byte(parts[0]))
+ if len(parts) == 1 {
+ return [32]byte{}, label
+ } else {
+ parentNode, parentLabel := ensParentNode(parts[1])
+ return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label
+ }
+}
+
+func ensNode(name string) common.Hash {
+ parentNode, parentLabel := ensParentNode(name)
+ return crypto.Keccak256Hash(parentNode[:], parentLabel[:])
+}
+
+func (self *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) {
+ resolverAddr, err := self.Resolver(node)
+ if err != nil {
+ return nil, err
+ }
+
+ resolver, err := contract.NewPublicResolver(resolverAddr, self.contractBackend)
+ if err != nil {
+ return nil, err
+ }
+
+ return &contract.PublicResolverSession{
+ Contract: resolver,
+ TransactOpts: self.TransactOpts,
+ }, nil
+}
+
+func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) {
+ registrarAddr, err := self.Owner(node)
+ if err != nil {
+ return nil, err
+ }
+
+ registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend)
+ if err != nil {
+ return nil, err
+ }
+
+ return &contract.FIFSRegistrarSession{
+ Contract: registrar,
+ TransactOpts: self.TransactOpts,
+ }, nil
+}
+
+// Resolve is a non-transactional call that returns the content hash associated with a name.
+func (self *ENS) Resolve(name string) (common.Hash, error) {
+ node := ensNode(name)
+
+ resolver, err := self.getResolver(node)
+ if err != nil {
+ return common.Hash{}, err
+ }
+
+ ret, err := resolver.Content(node)
+ if err != nil {
+ return common.Hash{}, err
+ }
+
+ return common.BytesToHash(ret[:]), nil
+}
+
+// Register registers a new domain name for the caller, making them the owner of the new name.
+// Only works if the registrar for the parent domain implements the FIFS registrar protocol.
+func (self *ENS) Register(name string) (*types.Transaction, error) {
+ parentNode, label := ensParentNode(name)
+
+ registrar, err := self.getRegistrar(parentNode)
+ if err != nil {
+ return nil, err
+ }
+
+ opts := self.TransactOpts
+ opts.GasLimit = big.NewInt(200000)
+ return registrar.Contract.Register(&opts, label, self.TransactOpts.From)
+}
+
+// SetContentHash sets the content hash associated with a name. Only works if the caller
+// owns the name, and the associated resolver implements a `setContent` function.
+func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) {
+ node := ensNode(name)
+
+ resolver, err := self.getResolver(node)
+ if err != nil {
+ return nil, err
+ }
+
+ opts := self.TransactOpts
+ opts.GasLimit = big.NewInt(200000)
+ return resolver.Contract.SetContent(&opts, node, hash)
+}
diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go
new file mode 100644
index 000000000..760966873
--- /dev/null
+++ b/contracts/ens/ens_test.go
@@ -0,0 +1,67 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ens
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+var (
+ key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ name = "my name on ENS"
+ hash = crypto.Sha3Hash([]byte("my content"))
+ addr = crypto.PubkeyToAddress(key.PublicKey)
+)
+
+func TestENS(t *testing.T) {
+ contractBackend := backends.NewSimulatedBackend(core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000000)})
+ transactOpts := bind.NewKeyedTransactor(key)
+ // Workaround for bug estimating gas in the call to Register
+ transactOpts.GasLimit = big.NewInt(1000000)
+
+ ens, err := DeployENS(transactOpts, contractBackend)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ contractBackend.Commit()
+
+ _, err = ens.Register(name)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ contractBackend.Commit()
+
+ _, err = ens.SetContentHash(name, hash)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ contractBackend.Commit()
+
+ vhost, err := ens.Resolve(name)
+ if err != nil {
+ t.Fatalf("expected no error, got %v", err)
+ }
+ if vhost != hash {
+ t.Fatalf("resolve error, expected %v, got %v", hash.Hex(), vhost.Hex())
+ }
+}
diff --git a/contracts/release/contract.go b/contracts/release/contract.go
new file mode 100644
index 000000000..6a0b09931
--- /dev/null
+++ b/contracts/release/contract.go
@@ -0,0 +1,432 @@
+// This file is an automatically generated Go binding. Do not modify as any
+// change will likely be lost upon the next re-generation!
+
+package release
+
+import (
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ReleaseOracleABI is the input ABI used to generate the binding from.
+const ReleaseOracleABI = `[{"constant":true,"inputs":[],"name":"proposedVersion","outputs":[{"name":"major","type":"uint32"},{"name":"minor","type":"uint32"},{"name":"patch","type":"uint32"},{"name":"commit","type":"bytes20"},{"name":"pass","type":"address[]"},{"name":"fail","type":"address[]"}],"type":"function"},{"constant":true,"inputs":[],"name":"signers","outputs":[{"name":"","type":"address[]"}],"type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"}],"name":"demote","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"authVotes","outputs":[{"name":"promote","type":"address[]"},{"name":"demote","type":"address[]"}],"type":"function"},{"constant":true,"inputs":[],"name":"currentVersion","outputs":[{"name":"major","type":"uint32"},{"name":"minor","type":"uint32"},{"name":"patch","type":"uint32"},{"name":"commit","type":"bytes20"},{"name":"time","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"nuke","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"authProposals","outputs":[{"name":"","type":"address[]"}],"type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"}],"name":"promote","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"major","type":"uint32"},{"name":"minor","type":"uint32"},{"name":"patch","type":"uint32"},{"name":"commit","type":"bytes20"}],"name":"release","outputs":[],"type":"function"},{"inputs":[{"name":"signers","type":"address[]"}],"type":"constructor"}]`
+
+// ReleaseOracleBin is the compiled bytecode used for deploying new contracts.
+const ReleaseOracleBin = `0x606060405260405161135338038061135383398101604052805101600081516000141561008457600160a060020a0333168152602081905260408120805460ff19166001908117909155805480820180835582818380158290116100ff576000838152602090206100ff9181019083015b8082111561012f5760008155600101610070565b5060005b815181101561011f5760016000600050600084848151811015610002576020908102909101810151600160a060020a03168252810191909152604001600020805460ff1916909117905560018054808201808355828183801582901161013357600083815260209020610133918101908301610070565b5050506000928352506020909120018054600160a060020a031916331790555b50506111df806101746000396000f35b5090565b50505091909060005260206000209001600084848151811015610002575050506020838102850101518154600160a060020a0319161790555060010161008856606060405236156100775760e060020a600035046326db7648811461007957806346f0975a1461019e5780635c3d005d1461020a57806364ed31fe146102935780639d888e861461038d578063bc8fbbf8146103b2578063bf8ecf9c146103fc578063d0e0813a14610468578063d67cbec914610479575b005b610496604080516020818101835260008083528351808301855281815260045460068054875181870281018701909852808852939687968796879691959463ffffffff818116956401000000008304821695604060020a840490921694606060020a938490049093029390926007929184919083018282801561012657602002820191906000526020600020905b8154600160a060020a0316815260019190910190602001808311610107575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561018357602002820191906000526020600020905b8154600160a060020a0316815260019190910190602001808311610164575b50505050509050955095509550955095509550909192939495565b6040805160208181018352600082526001805484518184028101840190955280855261055894928301828280156101ff57602002820191906000526020600020905b8154600160a060020a03168152600191909101906020018083116101e0575b505050505090505b90565b61007760043561066d8160005b600160a060020a033316600090815260208190526040812054819060ff161561070057600160a060020a038416815260026020526040812091505b8154811015610706578154600160a060020a033316908390839081101561000257600091825260209091200154600160a060020a0316141561075157610700565b6105a26004356040805160208181018352600080835283518083018552818152600160a060020a038616825260028352908490208054855181850281018501909652808652939491939092600184019291849183018282801561032057602002820191906000526020600020905b8154600160a060020a0316815260019190910190602001808311610301575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561037d57602002820191906000526020600020905b8154600160a060020a031681526001919091019060200180831161035e575b5050505050905091509150915091565b61062760006000600060006000600060086000508054905060001415610670576106f1565b6100776106f96000808080805b600160a060020a033316600090815260208190526040812054819060ff16156111b657821580156103f257506006546000145b15610c2e576111b6565b6040805160208181018352600082526003805484518184028101840190955280855261055894928301828280156101ff57602002820191906000526020600020908154600160a060020a03168152600191909101906020018083116101e0575b50505050509050610207565b61007760043561066d816001610217565b6100776004356024356044356064356107008484848460016103bf565b604051808763ffffffff1681526020018663ffffffff1681526020018563ffffffff168152602001846bffffffffffffffffffffffff1916815260200180602001806020018381038352858181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018381038252848181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019850505050505050505060405180910390f35b60405180806020018281038252838181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050019250505060405180910390f35b6040518080602001806020018381038352858181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f1509050018381038252848181518152602001915080519060200190602002808383829060006004602084601f0104600302600f01f15090500194505050505060405180910390f35b6040805163ffffffff9687168152948616602086015292909416838301526bffffffffffffffffffffffff19166060830152608082019290925290519081900360a00190f35b50565b600880546000198101908110156100025760009182526004027ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190508054600182015463ffffffff8281169950640100000000830481169850604060020a8304169650606060020a91829004909102945067ffffffffffffffff16925090505b509091929394565b565b505050505b50505050565b5060005b60018201548110156107595733600160a060020a03168260010160005082815481101561000257600091825260209091200154600160a060020a031614156107a357610700565b600101610252565b8154600014801561076e575060018201546000145b156107cb57600380546001810180835582818380158290116107ab578183600052602060002091820191016107ab9190610851565b60010161070a565b5050506000928352506020909120018054600160a060020a031916851790555b821561086957815460018101808455839190828183801582901161089e5760008381526020902061089e918101908301610851565b5050506000928352506020909120018054600160a060020a031916851790555b600160a060020a038416600090815260026020908152604082208054838255818452918320909291610b2f91908101905b808211156108655760008155600101610851565b5090565b816001016000508054806001018281815481835581811511610950578183600052602060002091820191016109509190610851565b5050506000928352506020909120018054600160a060020a031916331790556001548254600290910490116108d257610700565b8280156108f85750600160a060020a03841660009081526020819052604090205460ff16155b1561098757600160a060020a0384166000908152602081905260409020805460ff1916600190811790915580548082018083558281838015829011610800578183600052602060002091820191016108009190610851565b5050506000928352506020909120018054600160a060020a031916331790556001805490830154600290910490116108d257610700565b821580156109ad5750600160a060020a03841660009081526020819052604090205460ff165b156108205750600160a060020a0383166000908152602081905260408120805460ff191690555b6001548110156108205783600160a060020a0316600160005082815481101561000257600091825260209091200154600160a060020a03161415610aa357600180546000198101908110156100025760206000908120929052600180549290910154600160a060020a031691839081101561000257906000526020600020900160006101000a815481600160a060020a030219169083021790555060016000508054809190600190039090815481835581811511610aab57600083815260209020610aab918101908301610851565b6001016109d4565b5050600060048181556005805467ffffffffffffffff19169055600680548382558184529194509192508290610b05907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90810190610851565b5060018201805460008083559182526020909120610b2591810190610851565b5050505050610820565b5060018201805460008083559182526020909120610b4f91810190610851565b506000925050505b6003548110156107005783600160a060020a0316600360005082815481101561000257600091825260209091200154600160a060020a03161415610c2657600380546000198101908110156100025760206000908120929052600380549290910154600160a060020a031691839081101561000257906000526020600020900160006101000a815481600160a060020a0302191690830217905550600360005080548091906001900390908154818355818115116106fb576000838152602090206106fb918101908301610851565b600101610b57565b60065460001415610c8c576004805463ffffffff1916881767ffffffff0000000019166401000000008802176bffffffff00000000000000001916604060020a8702176bffffffffffffffffffffffff16606060020a808704021790555b828015610d08575060045463ffffffff8881169116141580610cc1575060045463ffffffff8781166401000000009092041614155b80610cde575060045463ffffffff868116604060020a9092041614155b80610d085750600454606060020a90819004026bffffffffffffffffffffffff1990811690851614155b15610d12576111b6565b506006905060005b8154811015610d5b578154600160a060020a033316908390839081101561000257600091825260209091200154600160a060020a03161415610da6576111b6565b5060005b6001820154811015610dae5733600160a060020a03168260010160005082815481101561000257600091825260209091200154600160a060020a03161415610de3576111b6565b600101610d1a565b8215610deb578154600181018084558391908281838015829011610e2057600083815260209020610e20918101908301610851565b600101610d5f565b816001016000508054806001018281815481835581811511610ea357818360005260206000209182019101610ea39190610851565b5050506000928352506020909120018054600160a060020a03191633179055600154825460029091049011610e54576111b6565b8215610eda576005805467ffffffffffffffff19164217905560088054600181018083558281838015829011610f2f57600402816004028360005260206000209182019101610f2f9190611048565b5050506000928352506020909120018054600160a060020a03191633179055600180549083015460029091049011610e54576111b6565b600060048181556005805467ffffffffffffffff191690556006805483825581845291929182906111bf907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90810190610851565b5050509190906000526020600020906004020160005060048054825463ffffffff191663ffffffff9182161780845582546401000000009081900483160267ffffffff000000001991909116178084558254604060020a908190049092169091026bffffffff00000000000000001991909116178083558154606060020a908190048102819004026bffffffffffffffffffffffff9190911617825560055460018301805467ffffffffffffffff191667ffffffffffffffff9092169190911790556006805460028401805482825560008281526020902094959491928392918201918582156110a75760005260206000209182015b828111156110a7578254825591600101919060010190611025565b505050506004015b8082111561086557600080825560018201805467ffffffffffffffff191690556002820180548282558183526020832083916110879190810190610851565b506001820180546000808355918252602090912061104091810190610851565b506110cd9291505b80821115610865578054600160a060020a03191681556001016110af565b505060018181018054918401805480835560008381526020902092938301929091821561111b5760005260206000209182015b8281111561111b578254825591600101919060010190611100565b506111279291506110af565b5050600060048181556005805467ffffffffffffffff191690556006805483825581845291975091955090935084925061118691507ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90810190610851565b50600182018054600080835591825260209091206111a691810190610851565b50505050506111b6565b50505050505b50505050505050565b50600182018054600080835591825260209091206111b09181019061085156`
+
+// DeployReleaseOracle deploys a new Ethereum contract, binding an instance of ReleaseOracle to it.
+func DeployReleaseOracle(auth *bind.TransactOpts, backend bind.ContractBackend, signers []common.Address) (common.Address, *types.Transaction, *ReleaseOracle, error) {
+ parsed, err := abi.JSON(strings.NewReader(ReleaseOracleABI))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(ReleaseOracleBin), backend, signers)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ReleaseOracle{ReleaseOracleCaller: ReleaseOracleCaller{contract: contract}, ReleaseOracleTransactor: ReleaseOracleTransactor{contract: contract}}, nil
+}
+
+// ReleaseOracle is an auto generated Go binding around an Ethereum contract.
+type ReleaseOracle struct {
+ ReleaseOracleCaller // Read-only binding to the contract
+ ReleaseOracleTransactor // Write-only binding to the contract
+}
+
+// ReleaseOracleCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ReleaseOracleCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ReleaseOracleTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ReleaseOracleTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ReleaseOracleSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ReleaseOracleSession struct {
+ Contract *ReleaseOracle // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ReleaseOracleCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ReleaseOracleCallerSession struct {
+ Contract *ReleaseOracleCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ReleaseOracleTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ReleaseOracleTransactorSession struct {
+ Contract *ReleaseOracleTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ReleaseOracleRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ReleaseOracleRaw struct {
+ Contract *ReleaseOracle // Generic contract binding to access the raw methods on
+}
+
+// ReleaseOracleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ReleaseOracleCallerRaw struct {
+ Contract *ReleaseOracleCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ReleaseOracleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ReleaseOracleTransactorRaw struct {
+ Contract *ReleaseOracleTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewReleaseOracle creates a new instance of ReleaseOracle, bound to a specific deployed contract.
+func NewReleaseOracle(address common.Address, backend bind.ContractBackend) (*ReleaseOracle, error) {
+ contract, err := bindReleaseOracle(address, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ReleaseOracle{ReleaseOracleCaller: ReleaseOracleCaller{contract: contract}, ReleaseOracleTransactor: ReleaseOracleTransactor{contract: contract}}, nil
+}
+
+// NewReleaseOracleCaller creates a new read-only instance of ReleaseOracle, bound to a specific deployed contract.
+func NewReleaseOracleCaller(address common.Address, caller bind.ContractCaller) (*ReleaseOracleCaller, error) {
+ contract, err := bindReleaseOracle(address, caller, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ReleaseOracleCaller{contract: contract}, nil
+}
+
+// NewReleaseOracleTransactor creates a new write-only instance of ReleaseOracle, bound to a specific deployed contract.
+func NewReleaseOracleTransactor(address common.Address, transactor bind.ContractTransactor) (*ReleaseOracleTransactor, error) {
+ contract, err := bindReleaseOracle(address, nil, transactor)
+ if err != nil {
+ return nil, err
+ }
+ return &ReleaseOracleTransactor{contract: contract}, nil
+}
+
+// bindReleaseOracle binds a generic wrapper to an already deployed contract.
+func bindReleaseOracle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor) (*bind.BoundContract, error) {
+ parsed, err := abi.JSON(strings.NewReader(ReleaseOracleABI))
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, parsed, caller, transactor), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_ReleaseOracle *ReleaseOracleRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _ReleaseOracle.Contract.ReleaseOracleCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_ReleaseOracle *ReleaseOracleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.ReleaseOracleTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_ReleaseOracle *ReleaseOracleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.ReleaseOracleTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_ReleaseOracle *ReleaseOracleCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error {
+ return _ReleaseOracle.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_ReleaseOracle *ReleaseOracleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_ReleaseOracle *ReleaseOracleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.contract.Transact(opts, method, params...)
+}
+
+// AuthProposals is a free data retrieval call binding the contract method 0xbf8ecf9c.
+//
+// Solidity: function authProposals() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleCaller) AuthProposals(opts *bind.CallOpts) ([]common.Address, error) {
+ var (
+ ret0 = new([]common.Address)
+ )
+ out := ret0
+ err := _ReleaseOracle.contract.Call(opts, out, "authProposals")
+ return *ret0, err
+}
+
+// AuthProposals is a free data retrieval call binding the contract method 0xbf8ecf9c.
+//
+// Solidity: function authProposals() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleSession) AuthProposals() ([]common.Address, error) {
+ return _ReleaseOracle.Contract.AuthProposals(&_ReleaseOracle.CallOpts)
+}
+
+// AuthProposals is a free data retrieval call binding the contract method 0xbf8ecf9c.
+//
+// Solidity: function authProposals() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleCallerSession) AuthProposals() ([]common.Address, error) {
+ return _ReleaseOracle.Contract.AuthProposals(&_ReleaseOracle.CallOpts)
+}
+
+// AuthVotes is a free data retrieval call binding the contract method 0x64ed31fe.
+//
+// Solidity: function authVotes(user address) constant returns(promote address[], demote address[])
+func (_ReleaseOracle *ReleaseOracleCaller) AuthVotes(opts *bind.CallOpts, user common.Address) (struct {
+ Promote []common.Address
+ Demote []common.Address
+}, error) {
+ ret := new(struct {
+ Promote []common.Address
+ Demote []common.Address
+ })
+ out := ret
+ err := _ReleaseOracle.contract.Call(opts, out, "authVotes", user)
+ return *ret, err
+}
+
+// AuthVotes is a free data retrieval call binding the contract method 0x64ed31fe.
+//
+// Solidity: function authVotes(user address) constant returns(promote address[], demote address[])
+func (_ReleaseOracle *ReleaseOracleSession) AuthVotes(user common.Address) (struct {
+ Promote []common.Address
+ Demote []common.Address
+}, error) {
+ return _ReleaseOracle.Contract.AuthVotes(&_ReleaseOracle.CallOpts, user)
+}
+
+// AuthVotes is a free data retrieval call binding the contract method 0x64ed31fe.
+//
+// Solidity: function authVotes(user address) constant returns(promote address[], demote address[])
+func (_ReleaseOracle *ReleaseOracleCallerSession) AuthVotes(user common.Address) (struct {
+ Promote []common.Address
+ Demote []common.Address
+}, error) {
+ return _ReleaseOracle.Contract.AuthVotes(&_ReleaseOracle.CallOpts, user)
+}
+
+// CurrentVersion is a free data retrieval call binding the contract method 0x9d888e86.
+//
+// Solidity: function currentVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, time uint256)
+func (_ReleaseOracle *ReleaseOracleCaller) CurrentVersion(opts *bind.CallOpts) (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Time *big.Int
+}, error) {
+ ret := new(struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Time *big.Int
+ })
+ out := ret
+ err := _ReleaseOracle.contract.Call(opts, out, "currentVersion")
+ return *ret, err
+}
+
+// CurrentVersion is a free data retrieval call binding the contract method 0x9d888e86.
+//
+// Solidity: function currentVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, time uint256)
+func (_ReleaseOracle *ReleaseOracleSession) CurrentVersion() (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Time *big.Int
+}, error) {
+ return _ReleaseOracle.Contract.CurrentVersion(&_ReleaseOracle.CallOpts)
+}
+
+// CurrentVersion is a free data retrieval call binding the contract method 0x9d888e86.
+//
+// Solidity: function currentVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, time uint256)
+func (_ReleaseOracle *ReleaseOracleCallerSession) CurrentVersion() (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Time *big.Int
+}, error) {
+ return _ReleaseOracle.Contract.CurrentVersion(&_ReleaseOracle.CallOpts)
+}
+
+// ProposedVersion is a free data retrieval call binding the contract method 0x26db7648.
+//
+// Solidity: function proposedVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, pass address[], fail address[])
+func (_ReleaseOracle *ReleaseOracleCaller) ProposedVersion(opts *bind.CallOpts) (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Pass []common.Address
+ Fail []common.Address
+}, error) {
+ ret := new(struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Pass []common.Address
+ Fail []common.Address
+ })
+ out := ret
+ err := _ReleaseOracle.contract.Call(opts, out, "proposedVersion")
+ return *ret, err
+}
+
+// ProposedVersion is a free data retrieval call binding the contract method 0x26db7648.
+//
+// Solidity: function proposedVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, pass address[], fail address[])
+func (_ReleaseOracle *ReleaseOracleSession) ProposedVersion() (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Pass []common.Address
+ Fail []common.Address
+}, error) {
+ return _ReleaseOracle.Contract.ProposedVersion(&_ReleaseOracle.CallOpts)
+}
+
+// ProposedVersion is a free data retrieval call binding the contract method 0x26db7648.
+//
+// Solidity: function proposedVersion() constant returns(major uint32, minor uint32, patch uint32, commit bytes20, pass address[], fail address[])
+func (_ReleaseOracle *ReleaseOracleCallerSession) ProposedVersion() (struct {
+ Major uint32
+ Minor uint32
+ Patch uint32
+ Commit [20]byte
+ Pass []common.Address
+ Fail []common.Address
+}, error) {
+ return _ReleaseOracle.Contract.ProposedVersion(&_ReleaseOracle.CallOpts)
+}
+
+// Signers is a free data retrieval call binding the contract method 0x46f0975a.
+//
+// Solidity: function signers() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleCaller) Signers(opts *bind.CallOpts) ([]common.Address, error) {
+ var (
+ ret0 = new([]common.Address)
+ )
+ out := ret0
+ err := _ReleaseOracle.contract.Call(opts, out, "signers")
+ return *ret0, err
+}
+
+// Signers is a free data retrieval call binding the contract method 0x46f0975a.
+//
+// Solidity: function signers() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleSession) Signers() ([]common.Address, error) {
+ return _ReleaseOracle.Contract.Signers(&_ReleaseOracle.CallOpts)
+}
+
+// Signers is a free data retrieval call binding the contract method 0x46f0975a.
+//
+// Solidity: function signers() constant returns(address[])
+func (_ReleaseOracle *ReleaseOracleCallerSession) Signers() ([]common.Address, error) {
+ return _ReleaseOracle.Contract.Signers(&_ReleaseOracle.CallOpts)
+}
+
+// Demote is a paid mutator transaction binding the contract method 0x5c3d005d.
+//
+// Solidity: function demote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleTransactor) Demote(opts *bind.TransactOpts, user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.contract.Transact(opts, "demote", user)
+}
+
+// Demote is a paid mutator transaction binding the contract method 0x5c3d005d.
+//
+// Solidity: function demote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleSession) Demote(user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Demote(&_ReleaseOracle.TransactOpts, user)
+}
+
+// Demote is a paid mutator transaction binding the contract method 0x5c3d005d.
+//
+// Solidity: function demote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleTransactorSession) Demote(user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Demote(&_ReleaseOracle.TransactOpts, user)
+}
+
+// Nuke is a paid mutator transaction binding the contract method 0xbc8fbbf8.
+//
+// Solidity: function nuke() returns()
+func (_ReleaseOracle *ReleaseOracleTransactor) Nuke(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReleaseOracle.contract.Transact(opts, "nuke")
+}
+
+// Nuke is a paid mutator transaction binding the contract method 0xbc8fbbf8.
+//
+// Solidity: function nuke() returns()
+func (_ReleaseOracle *ReleaseOracleSession) Nuke() (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Nuke(&_ReleaseOracle.TransactOpts)
+}
+
+// Nuke is a paid mutator transaction binding the contract method 0xbc8fbbf8.
+//
+// Solidity: function nuke() returns()
+func (_ReleaseOracle *ReleaseOracleTransactorSession) Nuke() (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Nuke(&_ReleaseOracle.TransactOpts)
+}
+
+// Promote is a paid mutator transaction binding the contract method 0xd0e0813a.
+//
+// Solidity: function promote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleTransactor) Promote(opts *bind.TransactOpts, user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.contract.Transact(opts, "promote", user)
+}
+
+// Promote is a paid mutator transaction binding the contract method 0xd0e0813a.
+//
+// Solidity: function promote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleSession) Promote(user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Promote(&_ReleaseOracle.TransactOpts, user)
+}
+
+// Promote is a paid mutator transaction binding the contract method 0xd0e0813a.
+//
+// Solidity: function promote(user address) returns()
+func (_ReleaseOracle *ReleaseOracleTransactorSession) Promote(user common.Address) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Promote(&_ReleaseOracle.TransactOpts, user)
+}
+
+// Release is a paid mutator transaction binding the contract method 0xd67cbec9.
+//
+// Solidity: function release(major uint32, minor uint32, patch uint32, commit bytes20) returns()
+func (_ReleaseOracle *ReleaseOracleTransactor) Release(opts *bind.TransactOpts, major uint32, minor uint32, patch uint32, commit [20]byte) (*types.Transaction, error) {
+ return _ReleaseOracle.contract.Transact(opts, "release", major, minor, patch, commit)
+}
+
+// Release is a paid mutator transaction binding the contract method 0xd67cbec9.
+//
+// Solidity: function release(major uint32, minor uint32, patch uint32, commit bytes20) returns()
+func (_ReleaseOracle *ReleaseOracleSession) Release(major uint32, minor uint32, patch uint32, commit [20]byte) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Release(&_ReleaseOracle.TransactOpts, major, minor, patch, commit)
+}
+
+// Release is a paid mutator transaction binding the contract method 0xd67cbec9.
+//
+// Solidity: function release(major uint32, minor uint32, patch uint32, commit bytes20) returns()
+func (_ReleaseOracle *ReleaseOracleTransactorSession) Release(major uint32, minor uint32, patch uint32, commit [20]byte) (*types.Transaction, error) {
+ return _ReleaseOracle.Contract.Release(&_ReleaseOracle.TransactOpts, major, minor, patch, commit)
+}
diff --git a/contracts/release/contract.sol b/contracts/release/contract.sol
new file mode 100644
index 000000000..fedf646c0
--- /dev/null
+++ b/contracts/release/contract.sol
@@ -0,0 +1,249 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// ReleaseOracle is an Ethereum contract to store the current and previous
+// versions of the go-ethereum implementation. Its goal is to allow Geth to
+// check for new releases automatically without the need to consult a central
+// repository.
+//
+// The contract takes a vote based approach on both assigning authorised signers
+// as well as signing off on new Geth releases.
+//
+// Note, when a signer is demoted, the currently pending release is auto-nuked.
+// The reason is to prevent suprises where a demotion actually tilts the votes
+// in favor of one voter party and pushing out a new release as a consequence of
+// a simple demotion.
+contract ReleaseOracle {
+ // Votes is an internal data structure to count votes on a specific proposal
+ struct Votes {
+ address[] pass; // List of signers voting to pass a proposal
+ address[] fail; // List of signers voting to fail a proposal
+ }
+
+ // Version is the version details of a particular Geth release
+ struct Version {
+ uint32 major; // Major version component of the release
+ uint32 minor; // Minor version component of the release
+ uint32 patch; // Patch version component of the release
+ bytes20 commit; // Git SHA1 commit hash of the release
+
+ uint64 time; // Timestamp of the release approval
+ Votes votes; // Votes that passed this release
+ }
+
+ // Oracle authorization details
+ mapping(address => bool) authorised; // Set of accounts allowed to vote on updating the contract
+ address[] voters; // List of addresses currently accepted as signers
+
+ // Various proposals being voted on
+ mapping(address => Votes) authProps; // Currently running user authorization proposals
+ address[] authPend; // List of addresses being voted on (map indexes)
+
+ Version verProp; // Currently proposed release being voted on
+ Version[] releases; // All the positively voted releases
+
+ // isSigner is a modifier to authorize contract transactions.
+ modifier isSigner() {
+ if (authorised[msg.sender]) {
+ _
+ }
+ }
+
+ // Constructor to assign the initial set of signers.
+ function ReleaseOracle(address[] signers) {
+ // If no signers were specified, assign the creator as the sole signer
+ if (signers.length == 0) {
+ authorised[msg.sender] = true;
+ voters.push(msg.sender);
+ return;
+ }
+ // Otherwise assign the individual signers one by one
+ for (uint i = 0; i < signers.length; i++) {
+ authorised[signers[i]] = true;
+ voters.push(signers[i]);
+ }
+ }
+
+ // signers is an accessor method to retrieve all te signers (public accessor
+ // generates an indexed one, not a retreive-all version).
+ function signers() constant returns(address[]) {
+ return voters;
+ }
+
+ // authProposals retrieves the list of addresses that authorization proposals
+ // are currently being voted on.
+ function authProposals() constant returns(address[]) {
+ return authPend;
+ }
+
+ // authVotes retrieves the current authorization votes for a particular user
+ // to promote him into the list of signers, or demote him from there.
+ function authVotes(address user) constant returns(address[] promote, address[] demote) {
+ return (authProps[user].pass, authProps[user].fail);
+ }
+
+ // currentVersion retrieves the semantic version, commit hash and release time
+ // of the currently votec active release.
+ function currentVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, uint time) {
+ if (releases.length == 0) {
+ return (0, 0, 0, 0, 0);
+ }
+ var release = releases[releases.length - 1];
+
+ return (release.major, release.minor, release.patch, release.commit, release.time);
+ }
+
+ // proposedVersion retrieves the semantic version, commit hash and the current
+ // votes for the next proposed release.
+ function proposedVersion() constant returns (uint32 major, uint32 minor, uint32 patch, bytes20 commit, address[] pass, address[] fail) {
+ return (verProp.major, verProp.minor, verProp.patch, verProp.commit, verProp.votes.pass, verProp.votes.fail);
+ }
+
+ // promote pitches in on a voting campaign to promote a new user to a signer
+ // position.
+ function promote(address user) {
+ updateSigner(user, true);
+ }
+
+ // demote pitches in on a voting campaign to demote an authorised user from
+ // its signer position.
+ function demote(address user) {
+ updateSigner(user, false);
+ }
+
+ // release votes for a particular version to be included as the next release.
+ function release(uint32 major, uint32 minor, uint32 patch, bytes20 commit) {
+ updateRelease(major, minor, patch, commit, true);
+ }
+
+ // nuke votes for the currently proposed version to not be included as the next
+ // release. Nuking doesn't require a specific version number for simplicity.
+ function nuke() {
+ updateRelease(0, 0, 0, 0, false);
+ }
+
+ // updateSigner marks a vote for changing the status of an Ethereum user, either
+ // for or against the user being an authorised signer.
+ function updateSigner(address user, bool authorize) internal isSigner {
+ // Gather the current votes and ensure we don't double vote
+ Votes votes = authProps[user];
+ for (uint i = 0; i < votes.pass.length; i++) {
+ if (votes.pass[i] == msg.sender) {
+ return;
+ }
+ }
+ for (i = 0; i < votes.fail.length; i++) {
+ if (votes.fail[i] == msg.sender) {
+ return;
+ }
+ }
+ // If no authorization proposal is open, add the user to the index for later lookups
+ if (votes.pass.length == 0 && votes.fail.length == 0) {
+ authPend.push(user);
+ }
+ // Cast the vote and return if the proposal cannot be resolved yet
+ if (authorize) {
+ votes.pass.push(msg.sender);
+ if (votes.pass.length <= voters.length / 2) {
+ return;
+ }
+ } else {
+ votes.fail.push(msg.sender);
+ if (votes.fail.length <= voters.length / 2) {
+ return;
+ }
+ }
+ // Proposal resolved in our favor, execute whatever we voted on
+ if (authorize && !authorised[user]) {
+ authorised[user] = true;
+ voters.push(user);
+ } else if (!authorize && authorised[user]) {
+ authorised[user] = false;
+
+ for (i = 0; i < voters.length; i++) {
+ if (voters[i] == user) {
+ voters[i] = voters[voters.length - 1];
+ voters.length--;
+
+ delete verProp; // Nuke any version proposal (no suprise releases!)
+ break;
+ }
+ }
+ }
+ // Finally delete the resolved proposal, index and garbage collect
+ delete authProps[user];
+
+ for (i = 0; i < authPend.length; i++) {
+ if (authPend[i] == user) {
+ authPend[i] = authPend[authPend.length - 1];
+ authPend.length--;
+ break;
+ }
+ }
+ }
+
+ // updateRelease votes for a particular version to be included as the next release,
+ // or for the currently proposed release to be nuked out.
+ function updateRelease(uint32 major, uint32 minor, uint32 patch, bytes20 commit, bool release) internal isSigner {
+ // Skip nuke votes if no proposal is pending
+ if (!release && verProp.votes.pass.length == 0) {
+ return;
+ }
+ // Mark a new release if no proposal is pending
+ if (verProp.votes.pass.length == 0) {
+ verProp.major = major;
+ verProp.minor = minor;
+ verProp.patch = patch;
+ verProp.commit = commit;
+ }
+ // Make sure positive votes match the current proposal
+ if (release && (verProp.major != major || verProp.minor != minor || verProp.patch != patch || verProp.commit != commit)) {
+ return;
+ }
+ // Gather the current votes and ensure we don't double vote
+ Votes votes = verProp.votes;
+ for (uint i = 0; i < votes.pass.length; i++) {
+ if (votes.pass[i] == msg.sender) {
+ return;
+ }
+ }
+ for (i = 0; i < votes.fail.length; i++) {
+ if (votes.fail[i] == msg.sender) {
+ return;
+ }
+ }
+ // Cast the vote and return if the proposal cannot be resolved yet
+ if (release) {
+ votes.pass.push(msg.sender);
+ if (votes.pass.length <= voters.length / 2) {
+ return;
+ }
+ } else {
+ votes.fail.push(msg.sender);
+ if (votes.fail.length <= voters.length / 2) {
+ return;
+ }
+ }
+ // Proposal resolved in our favor, execute whatever we voted on
+ if (release) {
+ verProp.time = uint64(now);
+ releases.push(verProp);
+ delete verProp;
+ } else {
+ delete verProp;
+ }
+ }
+}
diff --git a/contracts/release/contract_test.go b/contracts/release/contract_test.go
new file mode 100644
index 000000000..11a039992
--- /dev/null
+++ b/contracts/release/contract_test.go
@@ -0,0 +1,374 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package release
+
+import (
+ "crypto/ecdsa"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// setupReleaseTest creates a blockchain simulator and deploys a version oracle
+// contract for testing.
+func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.PrivateKey, *ReleaseOracle, *backends.SimulatedBackend) {
+ // Generate a new random account and a funded simulator
+ key, _ := crypto.GenerateKey()
+ auth := bind.NewKeyedTransactor(key)
+
+ accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}}
+ for _, key := range prefund {
+ accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)})
+ }
+ sim := backends.NewSimulatedBackend(accounts...)
+
+ // Deploy a version oracle contract, commit and return
+ _, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
+ if err != nil {
+ t.Fatalf("Failed to deploy version contract: %v", err)
+ }
+ sim.Commit()
+
+ return key, oracle, sim
+}
+
+// Tests that the version contract can be deployed and the creator is assigned
+// the sole authorized signer.
+func TestContractCreation(t *testing.T) {
+ key, oracle, _ := setupReleaseTest(t)
+
+ owner := crypto.PubkeyToAddress(key.PublicKey)
+ signers, err := oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Failed to retrieve list of signers: %v", err)
+ }
+ if len(signers) != 1 || signers[0] != owner {
+ t.Fatalf("Initial signer mismatch: have %v, want %v", signers, owner)
+ }
+}
+
+// Tests that subsequent signers can be promoted, each requiring half plus one
+// votes for it to pass through.
+func TestSignerPromotion(t *testing.T) {
+ // Prefund a few accounts to authorize with and create the oracle
+ keys := make([]*ecdsa.PrivateKey, 5)
+ for i := 0; i < len(keys); i++ {
+ keys[i], _ = crypto.GenerateKey()
+ }
+ key, oracle, sim := setupReleaseTest(t, keys...)
+
+ // Gradually promote the keys, until all are authorized
+ keys = append([]*ecdsa.PrivateKey{key}, keys...)
+ for i := 1; i < len(keys); i++ {
+ // Check that no votes are accepted from the not yet authed user
+ if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[i]), common.Address{}); err != nil {
+ t.Fatalf("Iter #%d: failed invalid promotion attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ pend, err := oracle.AuthProposals(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve active proposals: %v", i, err)
+ }
+ if len(pend) != 0 {
+ t.Fatalf("Iter #%d: proposal count mismatch: have %d, want 0", i, len(pend))
+ }
+ // Promote with half - 1 voters and check that the user's not yet authorized
+ for j := 0; j < i/2; j++ {
+ if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ signers, err := oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", i, err)
+ }
+ if len(signers) != i {
+ t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", i, len(signers), i)
+ }
+ // Promote with the last one needed to pass the promotion
+ if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[i/2]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion completion attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ signers, err = oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", i, err)
+ }
+ if len(signers) != i+1 {
+ t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", i, len(signers), i+1)
+ }
+ }
+}
+
+// Tests that subsequent signers can be demoted, each requiring half plus one
+// votes for it to pass through.
+func TestSignerDemotion(t *testing.T) {
+ // Prefund a few accounts to authorize with and create the oracle
+ keys := make([]*ecdsa.PrivateKey, 5)
+ for i := 0; i < len(keys); i++ {
+ keys[i], _ = crypto.GenerateKey()
+ }
+ key, oracle, sim := setupReleaseTest(t, keys...)
+
+ // Authorize all the keys as valid signers and verify cardinality
+ keys = append([]*ecdsa.PrivateKey{key}, keys...)
+ for i := 1; i < len(keys); i++ {
+ for j := 0; j <= i/2; j++ {
+ if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+ }
+ signers, err := oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Failed to retrieve list of signers: %v", err)
+ }
+ if len(signers) != len(keys) {
+ t.Fatalf("Signer count mismatch: have %v, want %v", len(signers), len(keys))
+ }
+ // Gradually demote users until we run out of signers
+ for i := len(keys) - 1; i >= 0; i-- {
+ // Demote with half - 1 voters and check that the user's not yet dropped
+ for j := 0; j < (i+1)/2; j++ {
+ if _, err = oracle.Demote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid demotion attempt: %v", len(keys)-i, err)
+ }
+ }
+ sim.Commit()
+
+ signers, err := oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", len(keys)-i, err)
+ }
+ if len(signers) != i+1 {
+ t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", len(keys)-i, len(signers), i+1)
+ }
+ // Demote with the last one needed to pass the demotion
+ if _, err = oracle.Demote(bind.NewKeyedTransactor(keys[(i+1)/2]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid demotion completion attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ signers, err = oracle.Signers(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve list of signers: %v", len(keys)-i, err)
+ }
+ if len(signers) != i {
+ t.Fatalf("Iter #%d: signer count mismatch: have %v, want %v", len(keys)-i, len(signers), i)
+ }
+ // Check that no votes are accepted from the already demoted users
+ if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[i]), common.Address{}); err != nil {
+ t.Fatalf("Iter #%d: failed invalid promotion attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ pend, err := oracle.AuthProposals(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve active proposals: %v", i, err)
+ }
+ if len(pend) != 0 {
+ t.Fatalf("Iter #%d: proposal count mismatch: have %d, want 0", i, len(pend))
+ }
+ }
+}
+
+// Tests that new versions can be released, honouring both voting rights as well
+// as the minimum required vote count.
+func TestVersionRelease(t *testing.T) {
+ // Prefund a few accounts to authorize with and create the oracle
+ keys := make([]*ecdsa.PrivateKey, 5)
+ for i := 0; i < len(keys); i++ {
+ keys[i], _ = crypto.GenerateKey()
+ }
+ key, oracle, sim := setupReleaseTest(t, keys...)
+
+ // Track the "current release"
+ var (
+ verMajor = uint32(0)
+ verMinor = uint32(0)
+ verPatch = uint32(0)
+ verCommit = [20]byte{}
+ )
+ // Gradually push releases, always requiring more signers than previously
+ keys = append([]*ecdsa.PrivateKey{key}, keys...)
+ for i := 1; i < len(keys); i++ {
+ // Check that no votes are accepted from the not yet authed user
+ if _, err := oracle.Release(bind.NewKeyedTransactor(keys[i]), 0, 0, 0, [20]byte{0}); err != nil {
+ t.Fatalf("Iter #%d: failed invalid release attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ prop, err := oracle.ProposedVersion(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve active proposal: %v", i, err)
+ }
+ if len(prop.Pass) != 0 {
+ t.Fatalf("Iter #%d: proposal vote count mismatch: have %d, want 0", i, len(prop.Pass))
+ }
+ // Authorize the user to make releases
+ for j := 0; j <= i/2; j++ {
+ if _, err = oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ // Propose release with half voters and check that the release does not yet go through
+ for j := 0; j < (i+1)/2; j++ {
+ if _, err = oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil {
+ t.Fatalf("Iter #%d: failed valid release attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ ver, err := oracle.CurrentVersion(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve current version: %v", i, err)
+ }
+ if ver.Major != verMajor || ver.Minor != verMinor || ver.Patch != verPatch || ver.Commit != verCommit {
+ t.Fatalf("Iter #%d: version mismatch: have %d.%d.%d-%x, want %d.%d.%d-%x", i, ver.Major, ver.Minor, ver.Patch, ver.Commit, verMajor, verMinor, verPatch, verCommit)
+ }
+
+ // Pass the release and check that it became the next version
+ verMajor, verMinor, verPatch, verCommit = uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}
+ if _, err = oracle.Release(bind.NewKeyedTransactor(keys[(i+1)/2]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil {
+ t.Fatalf("Iter #%d: failed valid release completion attempt: %v", i, err)
+ }
+ sim.Commit()
+
+ ver, err = oracle.CurrentVersion(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve current version: %v", i, err)
+ }
+ if ver.Major != verMajor || ver.Minor != verMinor || ver.Patch != verPatch || ver.Commit != verCommit {
+ t.Fatalf("Iter #%d: version mismatch: have %d.%d.%d-%x, want %d.%d.%d-%x", i, ver.Major, ver.Minor, ver.Patch, ver.Commit, verMajor, verMinor, verPatch, verCommit)
+ }
+ }
+}
+
+// Tests that proposed versions can be nuked out of existence.
+func TestVersionNuking(t *testing.T) {
+ // Prefund a few accounts to authorize with and create the oracle
+ keys := make([]*ecdsa.PrivateKey, 9)
+ for i := 0; i < len(keys); i++ {
+ keys[i], _ = crypto.GenerateKey()
+ }
+ key, oracle, sim := setupReleaseTest(t, keys...)
+
+ // Authorize all the keys as valid signers
+ keys = append([]*ecdsa.PrivateKey{key}, keys...)
+ for i := 1; i < len(keys); i++ {
+ for j := 0; j <= i/2; j++ {
+ if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+ }
+ // Propose releases with more and more keys, always retaining enough users to nuke the proposals
+ for i := 1; i < (len(keys)+1)/2; i++ {
+ // Propose release with an initial set of signers
+ for j := 0; j < i; j++ {
+ if _, err := oracle.Release(bind.NewKeyedTransactor(keys[j]), uint32(i), uint32(i+1), uint32(i+2), [20]byte{byte(i + 3)}); err != nil {
+ t.Fatalf("Iter #%d: failed valid proposal attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ prop, err := oracle.ProposedVersion(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve active proposal: %v", i, err)
+ }
+ if len(prop.Pass) != i {
+ t.Fatalf("Iter #%d: proposal vote count mismatch: have %d, want %d", i, len(prop.Pass), i)
+ }
+ // Nuke the release with half+1 voters
+ for j := i; j <= i+(len(keys)+1)/2; j++ {
+ if _, err := oracle.Nuke(bind.NewKeyedTransactor(keys[j])); err != nil {
+ t.Fatalf("Iter #%d: failed valid nuke attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ prop, err = oracle.ProposedVersion(nil)
+ if err != nil {
+ t.Fatalf("Iter #%d: failed to retrieve active proposal: %v", i, err)
+ }
+ if len(prop.Pass) != 0 || len(prop.Fail) != 0 {
+ t.Fatalf("Iter #%d: proposal vote count mismatch: have %d/%d pass/fail, want 0/0", i, len(prop.Pass), len(prop.Fail))
+ }
+ }
+}
+
+// Tests that demoting a signer will auto-nuke the currently pending release.
+func TestVersionAutoNuke(t *testing.T) {
+ // Prefund a few accounts to authorize with and create the oracle
+ keys := make([]*ecdsa.PrivateKey, 5)
+ for i := 0; i < len(keys); i++ {
+ keys[i], _ = crypto.GenerateKey()
+ }
+ key, oracle, sim := setupReleaseTest(t, keys...)
+
+ // Authorize all the keys as valid signers
+ keys = append([]*ecdsa.PrivateKey{key}, keys...)
+ for i := 1; i < len(keys); i++ {
+ for j := 0; j <= i/2; j++ {
+ if _, err := oracle.Promote(bind.NewKeyedTransactor(keys[j]), crypto.PubkeyToAddress(keys[i].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid promotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+ }
+ // Make a release proposal and check it's existence
+ if _, err := oracle.Release(bind.NewKeyedTransactor(keys[0]), 1, 2, 3, [20]byte{4}); err != nil {
+ t.Fatalf("Failed valid proposal attempt: %v", err)
+ }
+ sim.Commit()
+
+ prop, err := oracle.ProposedVersion(nil)
+ if err != nil {
+ t.Fatalf("Failed to retrieve active proposal: %v", err)
+ }
+ if len(prop.Pass) != 1 {
+ t.Fatalf("Proposal vote count mismatch: have %d, want 1", len(prop.Pass))
+ }
+ // Demote a signer and check release proposal deletion
+ for i := 0; i <= len(keys)/2; i++ {
+ if _, err := oracle.Demote(bind.NewKeyedTransactor(keys[i]), crypto.PubkeyToAddress(keys[len(keys)-1].PublicKey)); err != nil {
+ t.Fatalf("Iter #%d: failed valid demotion attempt: %v", i, err)
+ }
+ }
+ sim.Commit()
+
+ prop, err = oracle.ProposedVersion(nil)
+ if err != nil {
+ t.Fatalf("Failed to retrieve active proposal: %v", err)
+ }
+ if len(prop.Pass) != 0 {
+ t.Fatalf("Proposal vote count mismatch: have %d, want 0", len(prop.Pass))
+ }
+}
diff --git a/contracts/release/release.go b/contracts/release/release.go
new file mode 100644
index 000000000..5a6665dba
--- /dev/null
+++ b/contracts/release/release.go
@@ -0,0 +1,152 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package release contains the node service that tracks client releases.
+package release
+
+//go:generate abigen --sol ./contract.sol --pkg release --out ./contract.go
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
+ "golang.org/x/net/context"
+)
+
+// Interval to check for new releases
+const releaseRecheckInterval = time.Hour
+
+// Config contains the configurations of the release service.
+type Config struct {
+ Oracle common.Address // Ethereum address of the release oracle
+ Major uint32 // Major version component of the release
+ Minor uint32 // Minor version component of the release
+ Patch uint32 // Patch version component of the release
+ Commit [20]byte // Git SHA1 commit hash of the release
+}
+
+// ReleaseService is a node service that periodically checks the blockchain for
+// newly released versions of the client being run and issues a warning to the
+// user about it.
+type ReleaseService struct {
+ config Config // Current version to check releases against
+ oracle *ReleaseOracle // Native binding to the release oracle contract
+ quit chan chan error // Quit channel to terminate the version checker
+}
+
+// NewReleaseService creates a new service to periodically check for new client
+// releases and notify the user of such.
+func NewReleaseService(ctx *node.ServiceContext, config Config) (node.Service, error) {
+ // Retrieve the Ethereum service dependency to access the blockchain
+ var ethereum *eth.Ethereum
+ if err := ctx.Service(&ethereum); err != nil {
+ return nil, err
+ }
+ // Construct the release service
+ contract, err := NewReleaseOracle(config.Oracle, eth.NewContractBackend(ethereum))
+ if err != nil {
+ return nil, err
+ }
+ return &ReleaseService{
+ config: config,
+ oracle: contract,
+ quit: make(chan chan error),
+ }, nil
+}
+
+// Protocols returns an empty list of P2P protocols as the release service does
+// not have a networking component.
+func (r *ReleaseService) Protocols() []p2p.Protocol { return nil }
+
+// APIs returns an empty list of RPC descriptors as the release service does not
+// expose any functioanlity to the outside world.
+func (r *ReleaseService) APIs() []rpc.API { return nil }
+
+// Start spawns the periodic version checker goroutine
+func (r *ReleaseService) Start(server *p2p.Server) error {
+ go r.checker()
+ return nil
+}
+
+// Stop terminates all goroutines belonging to the service, blocking until they
+// are all terminated.
+func (r *ReleaseService) Stop() error {
+ errc := make(chan error)
+ r.quit <- errc
+ return <-errc
+}
+
+// checker runs indefinitely in the background, periodically checking for new
+// client releases.
+func (r *ReleaseService) checker() {
+ // Set up the timers to periodically check for releases
+ timer := time.NewTimer(0) // Immediately fire a version check
+ defer timer.Stop()
+
+ for {
+ select {
+ // If the time arrived, check for a new release
+ case <-timer.C:
+ // Rechedule the timer before continuing
+ timer.Reset(releaseRecheckInterval)
+
+ // Retrieve the current version, and handle missing contracts gracefully
+ ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
+ opts := &bind.CallOpts{Context: ctx}
+ version, err := r.oracle.CurrentVersion(opts)
+ if err != nil {
+ if err == bind.ErrNoCode {
+ glog.V(logger.Debug).Infof("Release oracle not found at %x", r.config.Oracle)
+ continue
+ }
+ glog.V(logger.Error).Infof("Failed to retrieve current release: %v", err)
+ continue
+ }
+ // Version was successfully retrieved, notify if newer than ours
+ if version.Major > r.config.Major ||
+ (version.Major == r.config.Major && version.Minor > r.config.Minor) ||
+ (version.Major == r.config.Major && version.Minor == r.config.Minor && version.Patch > r.config.Patch) {
+
+ warning := fmt.Sprintf("Client v%d.%d.%d-%x seems older than the latest upstream release v%d.%d.%d-%x",
+ r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
+ howtofix := fmt.Sprintf("Please check https://github.com/ethereum/go-ethereum/releases for new releases")
+ separator := strings.Repeat("-", len(warning))
+
+ glog.V(logger.Warn).Info(separator)
+ glog.V(logger.Warn).Info(warning)
+ glog.V(logger.Warn).Info(howtofix)
+ glog.V(logger.Warn).Info(separator)
+ } else {
+ glog.V(logger.Debug).Infof("Client v%d.%d.%d-%x seems up to date with upstream v%d.%d.%d-%x",
+ r.config.Major, r.config.Minor, r.config.Patch, r.config.Commit[:4], version.Major, version.Minor, version.Patch, version.Commit[:4])
+ }
+
+ // If termination was requested, return
+ case errc := <-r.quit:
+ errc <- nil
+ return
+ }
+ }
+}