From 4a8eb1af3f6e279ae9498e15ea296324193a483f Mon Sep 17 00:00:00 2001
From: Benjamin Bollen <ben@erisindustries.com>
Date: Wed, 8 Jun 2016 12:22:40 +0200
Subject: [PATCH] Implement definitions.Pipe for manager/ErisMint/pipe.go

---
 core/core.go                              |  10 +-
 manager/eris-mint/account/account.go      |  90 ------
 manager/eris-mint/account/priv_account.go |  85 ------
 manager/eris-mint/accounts.go             | 224 +++++++++++++++
 manager/eris-mint/blockchain.go           | 296 ++++++++++++++++++++
 manager/eris-mint/consensus.go            |  65 +++++
 manager/eris-mint/eris-mint.go            |  10 +-
 manager/eris-mint/events.go               |  46 +++
 manager/eris-mint/filters.go              | 210 ++++++++++++++
 manager/eris-mint/namereg.go              | 241 ++++++++++++++++
 manager/eris-mint/net.go                  |  70 +++++
 manager/eris-mint/pipe.go                 |   9 +-
 manager/eris-mint/transactor.go           | 323 ++++++++++++++++++++++
 13 files changed, 1491 insertions(+), 188 deletions(-)
 delete mode 100644 manager/eris-mint/account/account.go
 delete mode 100644 manager/eris-mint/account/priv_account.go
 create mode 100644 manager/eris-mint/accounts.go
 create mode 100644 manager/eris-mint/blockchain.go
 create mode 100644 manager/eris-mint/consensus.go
 create mode 100644 manager/eris-mint/events.go
 create mode 100644 manager/eris-mint/filters.go
 create mode 100644 manager/eris-mint/namereg.go
 create mode 100644 manager/eris-mint/net.go
 create mode 100644 manager/eris-mint/transactor.go

diff --git a/core/core.go b/core/core.go
index 179c64ff..ed17d341 100644
--- a/core/core.go
+++ b/core/core.go
@@ -48,14 +48,14 @@ func NewCore(chainId, genesisFile string, consensusConfig *config.ModuleConfig,
   if err != nil {
     return nil, fmt.Errorf("PLACEHOLDER")
   }
-  // pass the
+  // pass the consensus engine into the pipe
   consensus.LoadConsensusEngineInPipe(consensusConfig, pipe)
 
 
-  // create state
-  // from genesis
-  // create event switch
-  // give state and evsw to app
+  // [x] create state
+  // [x] from genesis
+  // [x] create event switch
+  // [x] give state and evsw to app
   // give app to consensus
   // create new Pipe
   // give app
diff --git a/manager/eris-mint/account/account.go b/manager/eris-mint/account/account.go
deleted file mode 100644
index 62e1a820..00000000
--- a/manager/eris-mint/account/account.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package account
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-
-	ptypes "github.com/eris-ltd/eris-db/permission/types"
-	. "github.com/tendermint/go-common"
-	"github.com/tendermint/go-crypto"
-	"github.com/tendermint/go-merkle"
-	"github.com/tendermint/go-wire"
-)
-
-// Signable is an interface for all signable things.
-// It typically removes signatures before serializing.
-type Signable interface {
-	WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
-}
-
-// SignBytes is a convenience method for getting the bytes to sign of a Signable.
-func SignBytes(chainID string, o Signable) []byte {
-	buf, n, err := new(bytes.Buffer), new(int), new(error)
-	o.WriteSignBytes(chainID, buf, n, err)
-	if *err != nil {
-		PanicCrisis(err)
-	}
-	return buf.Bytes()
-}
-
-// HashSignBytes is a convenience method for getting the hash of the bytes of a signable
-func HashSignBytes(chainID string, o Signable) []byte {
-	return merkle.SimpleHashFromBinary(SignBytes(chainID, o))
-}
-
-//-----------------------------------------------------------------------------
-
-// Account resides in the application state, and is mutated by transactions
-// on the blockchain.
-// Serialized by wire.[read|write]Reflect
-type Account struct {
-	Address     []byte        `json:"address"`
-	PubKey      crypto.PubKey `json:"pub_key"`
-	Sequence    int           `json:"sequence"`
-	Balance     int64         `json:"balance"`
-	Code        []byte        `json:"code"`         // VM code
-	StorageRoot []byte        `json:"storage_root"` // VM storage merkle root.
-
-	Permissions ptypes.AccountPermissions `json:"permissions"`
-}
-
-func (acc *Account) Copy() *Account {
-	accCopy := *acc
-	return &accCopy
-}
-
-func (acc *Account) String() string {
-	if acc == nil {
-		return "nil-Account"
-	}
-	return fmt.Sprintf("Account{%X:%v B:%v C:%v S:%X P:%s}", acc.Address, acc.PubKey, acc.Balance, len(acc.Code), acc.StorageRoot, acc.Permissions)
-}
-
-func AccountEncoder(o interface{}, w io.Writer, n *int, err *error) {
-	wire.WriteBinary(o.(*Account), w, n, err)
-}
-
-func AccountDecoder(r io.Reader, n *int, err *error) interface{} {
-	return wire.ReadBinary(&Account{}, r, 0, n, err)
-}
-
-var AccountCodec = wire.Codec{
-	Encode: AccountEncoder,
-	Decode: AccountDecoder,
-}
-
-func EncodeAccount(acc *Account) []byte {
-	w := new(bytes.Buffer)
-	var n int
-	var err error
-	AccountEncoder(acc, w, &n, &err)
-	return w.Bytes()
-}
-
-func DecodeAccount(accBytes []byte) *Account {
-	var n int
-	var err error
-	acc := AccountDecoder(bytes.NewBuffer(accBytes), &n, &err)
-	return acc.(*Account)
-}
diff --git a/manager/eris-mint/account/priv_account.go b/manager/eris-mint/account/priv_account.go
deleted file mode 100644
index eb5f424f..00000000
--- a/manager/eris-mint/account/priv_account.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package account
-
-import (
-	"github.com/tendermint/ed25519"
-	. "github.com/tendermint/go-common"
-	"github.com/tendermint/go-crypto"
-	"github.com/tendermint/go-wire"
-)
-
-type PrivAccount struct {
-	Address []byte         `json:"address"`
-	PubKey  crypto.PubKey  `json:"pub_key"`
-	PrivKey crypto.PrivKey `json:"priv_key"`
-}
-
-func (pA *PrivAccount) Generate(index int) *PrivAccount {
-	newPrivKey := pA.PrivKey.(crypto.PrivKeyEd25519).Generate(index)
-	newPubKey := newPrivKey.PubKey()
-	newAddress := newPubKey.Address()
-	return &PrivAccount{
-		Address: newAddress,
-		PubKey:  newPubKey,
-		PrivKey: newPrivKey,
-	}
-}
-
-func (pA *PrivAccount) Sign(chainID string, o Signable) crypto.Signature {
-	return pA.PrivKey.Sign(SignBytes(chainID, o))
-}
-
-func (pA *PrivAccount) String() string {
-	return Fmt("PrivAccount{%X}", pA.Address)
-}
-
-//----------------------------------------
-
-// Generates a new account with private key.
-func GenPrivAccount() *PrivAccount {
-	privKeyBytes := new([64]byte)
-	copy(privKeyBytes[:32], crypto.CRandBytes(32))
-	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
-
-// Generates 32 priv key bytes from secret
-func GenPrivKeyBytesFromSecret(secret string) []byte {
-	return wire.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes.
-}
-
-// Generates a new account with private key from SHA256 hash of a secret
-func GenPrivAccountFromSecret(secret string) *PrivAccount {
-	privKey32 := GenPrivKeyBytesFromSecret(secret)
-	privKeyBytes := new([64]byte)
-	copy(privKeyBytes[:32], privKey32)
-	pubKeyBytes := ed25519.MakePublicKey(privKeyBytes)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(*privKeyBytes)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
-
-func GenPrivAccountFromPrivKeyBytes(privKeyBytes []byte) *PrivAccount {
-	if len(privKeyBytes) != 64 {
-		PanicSanity(Fmt("Expected 64 bytes but got %v", len(privKeyBytes)))
-	}
-	var privKeyArray [64]byte
-	copy(privKeyArray[:], privKeyBytes)
-	pubKeyBytes := ed25519.MakePublicKey(&privKeyArray)
-	pubKey := crypto.PubKeyEd25519(*pubKeyBytes)
-	privKey := crypto.PrivKeyEd25519(privKeyArray)
-	return &PrivAccount{
-		Address: pubKey.Address(),
-		PubKey:  pubKey,
-		PrivKey: privKey,
-	}
-}
diff --git a/manager/eris-mint/accounts.go b/manager/eris-mint/accounts.go
new file mode 100644
index 00000000..9af21563
--- /dev/null
+++ b/manager/eris-mint/accounts.go
@@ -0,0 +1,224 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Accounts is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+  "bytes"
+  "encoding/hex"
+  "fmt"
+  "sync"
+
+  tendermint_common "github.com/tendermint/go-common"
+
+  account    "github.com/eris-ltd/eris-db/account"
+  core_types "github.com/eris-ltd/eris-db/core/types"
+)
+
+// The accounts struct has methods for working with accounts.
+type accounts struct {
+  erisMint      *ErisMint
+  filterFactory *FilterFactory
+}
+
+func newAccounts(erisMint *ErisMint) *accounts {
+  ff := NewFilterFactory()
+
+  ff.RegisterFilterPool("code", &sync.Pool{
+    New: func() interface{} {
+      return &AccountCodeFilter{}
+    },
+  })
+
+  ff.RegisterFilterPool("balance", &sync.Pool{
+    New: func() interface{} {
+      return &AccountBalanceFilter{}
+    },
+  })
+
+  return &accounts{erisMint, ff}
+
+}
+
+// Generate a new Private Key Account.
+func (this *accounts) GenPrivAccount() (*account.PrivAccount, error) {
+  pa := account.GenPrivAccount()
+  return pa, nil
+}
+
+// Generate a new Private Key Account.
+func (this *accounts) GenPrivAccountFromKey(privKey []byte) (
+  *account.PrivAccount, error) {
+  if len(privKey) != 64 {
+    return nil, fmt.Errorf("Private key is not 64 bytes long.")
+  }
+  fmt.Printf("PK BYTES FROM ACCOUNTS: %x\n", privKey)
+  pa := account.GenPrivAccountFromPrivKeyBytes(privKey)
+  return pa, nil
+}
+
+// Get all accounts.
+func (this *accounts) Accounts(fda []*FilterData) (*core_types.AccountList,
+  error) {
+  accounts := make([]*account.Account, 0)
+  state := this.erisMint.GetState()
+  filter, err := this.filterFactory.NewFilter(fda)
+  if err != nil {
+    return nil, fmt.Errorf("Error in query: " + err.Error())
+  }
+  state.GetAccounts().Iterate(func(key, value []byte) bool {
+    acc := account.DecodeAccount(value)
+    if filter.Match(acc) {
+      accounts = append(accounts, acc)
+    }
+    return false
+  })
+  return &core_types.AccountList{accounts}, nil
+}
+
+// Get an account.
+func (this *accounts) Account(address []byte) (*account.Account, error) {
+  cache := this.erisMint.GetState() // NOTE: we want to read from mempool!
+  acc := cache.GetAccount(address)
+  if acc == nil {
+    acc = this.newAcc(address)
+  }
+  return acc, nil
+}
+
+// Get the value stored at 'key' in the account with address 'address'
+// Both the key and value is returned.
+func (this *accounts) StorageAt(address, key []byte) (*core_types.StorageItem,
+  error) {
+  state := this.erisMint.GetState()
+  account := state.GetAccount(address)
+  if account == nil {
+    return &core_types.StorageItem{key, []byte{}}, nil
+  }
+  storageRoot := account.StorageRoot
+  storageTree := state.LoadStorage(storageRoot)
+
+  _, value, _ := storageTree.Get(tendermint_common.LeftPadWord256(key).Bytes())
+  if value == nil {
+    return &core_types.StorageItem{key, []byte{}}, nil
+  }
+  return &core_types.StorageItem{key, value}, nil
+}
+
+// Get the storage of the account with address 'address'.
+func (this *accounts) Storage(address []byte) (*core_types.Storage, error) {
+
+  state := this.erisMint.GetState()
+  account := state.GetAccount(address)
+  storageItems := make([]core_types.StorageItem, 0)
+  if account == nil {
+    return &core_types.Storage{nil, storageItems}, nil
+  }
+  storageRoot := account.StorageRoot
+  storageTree := state.LoadStorage(storageRoot)
+
+  storageTree.Iterate(func(key, value []byte) bool {
+    storageItems = append(storageItems, core_types.StorageItem{
+      key, value})
+    return false
+  })
+  return &core_types.Storage{storageRoot, storageItems}, nil
+}
+
+// Create a new account.
+func (this *accounts) newAcc(address []byte) *account.Account {
+  return &account.Account{
+    Address:     address,
+    PubKey:      nil,
+    Sequence:    0,
+    Balance:     0,
+    Code:        nil,
+    StorageRoot: nil,
+  }
+}
+
+// Filter for account code.
+// Ops: == or !=
+// Could be used to match against nil, to see if an account is a contract account.
+type AccountCodeFilter struct {
+  op    string
+  value []byte
+  match func([]byte, []byte) bool
+}
+
+func (this *AccountCodeFilter) Configure(fd *FilterData) error {
+  op := fd.Op
+  val, err := hex.DecodeString(fd.Value)
+
+  if err != nil {
+    return fmt.Errorf("Wrong value type.")
+  }
+  if op == "==" {
+    this.match = func(a, b []byte) bool {
+      return bytes.Equal(a, b)
+    }
+  } else if op == "!=" {
+    this.match = func(a, b []byte) bool {
+      return !bytes.Equal(a, b)
+    }
+  } else {
+    return fmt.Errorf("Op: " + this.op + " is not supported for 'code' filtering")
+  }
+  this.op = op
+  this.value = val
+  return nil
+}
+
+func (this *AccountCodeFilter) Match(v interface{}) bool {
+  acc, ok := v.(*account.Account)
+  if !ok {
+    return false
+  }
+  return this.match(acc.Code, this.value)
+}
+
+// Filter for account balance.
+// Ops: All
+type AccountBalanceFilter struct {
+  op    string
+  value int64
+  match func(int64, int64) bool
+}
+
+func (this *AccountBalanceFilter) Configure(fd *FilterData) error {
+  val, err := ParseNumberValue(fd.Value)
+  if err != nil {
+    return err
+  }
+  match, err2 := GetRangeFilter(fd.Op, "balance")
+  if err2 != nil {
+    return err2
+  }
+  this.match = match
+  this.op = fd.Op
+  this.value = val
+  return nil
+}
+
+func (this *AccountBalanceFilter) Match(v interface{}) bool {
+  acc, ok := v.(*account.Account)
+  if !ok {
+    return false
+  }
+  return this.match(int64(acc.Balance), this.value)
+}
diff --git a/manager/eris-mint/blockchain.go b/manager/eris-mint/blockchain.go
new file mode 100644
index 00000000..760500f9
--- /dev/null
+++ b/manager/eris-mint/blockchain.go
@@ -0,0 +1,296 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Blockchain is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"sync"
+
+  dbm "github.com/tendermint/go-db"
+  "github.com/tendermint/tendermint/types"
+
+  core_types "github.com/eris-ltd/eris-db/core/types"
+	"github.com/eris-ltd/eris-db/manager/eris-mint/state"
+)
+
+const BLOCK_MAX = 50
+
+type BlockStore interface {
+	Height() int
+	LoadBlockMeta(height int) *types.BlockMeta
+	LoadBlock(height int) *types.Block
+}
+
+// The blockchain struct.
+type blockchain struct {
+	chainID       string
+	genDocFile    string // XXX
+	blockStore    BlockStore
+	filterFactory *FilterFactory
+}
+
+func newBlockchain(chainID, genDocFile string, blockStore BlockStore) *blockchain {
+	ff := NewFilterFactory()
+
+	ff.RegisterFilterPool("height", &sync.Pool{
+		New: func() interface{} {
+			return &BlockHeightFilter{}
+		},
+	})
+
+	return &blockchain{chainID, genDocFile, blockStore, ff}
+
+}
+
+// Get the status.
+func (this *blockchain) Info() (*core_types.BlockchainInfo, error) {
+	db := dbm.NewMemDB()
+	_, genesisState := state.MakeGenesisStateFromFile(db, this.genDocFile)
+	genesisHash := genesisState.Hash()
+	latestHeight := this.blockStore.Height()
+
+	var latestBlockMeta *types.BlockMeta
+
+	if latestHeight != 0 {
+		latestBlockMeta = this.blockStore.LoadBlockMeta(latestHeight)
+	}
+
+	return &core_types.BlockchainInfo{
+		this.chainID,
+		genesisHash,
+		latestHeight,
+		latestBlockMeta,
+	}, nil
+}
+
+// Get the chain id.
+func (this *blockchain) ChainId() (string, error) {
+	return this.chainID, nil
+}
+
+// Get the hash of the genesis block.
+func (this *blockchain) GenesisHash() ([]byte, error) {
+	db := dbm.NewMemDB()
+	_, genesisState := state.MakeGenesisStateFromFile(db, this.genDocFile)
+	return genesisState.Hash(), nil
+}
+
+// Get the latest block height.
+func (this *blockchain) LatestBlockHeight() (int, error) {
+	return this.blockStore.Height(), nil
+}
+
+// Get the latest block.
+func (this *blockchain) LatestBlock() (*types.Block, error) {
+	return this.Block(this.blockStore.Height())
+}
+
+// Get the blocks from 'minHeight' to 'maxHeight'.
+// TODO Caps on total number of blocks should be set.
+func (this *blockchain) Blocks(fda []*FilterData) (*core_types.Blocks, error) {
+	newFda := fda
+	var minHeight int
+	var maxHeight int
+	height := this.blockStore.Height()
+	if height == 0 {
+		return &core_types.Blocks{0, 0, []*types.BlockMeta{}}, nil
+	}
+	// Optimization. Break any height filters out. Messy but makes sure we don't
+	// fetch more blocks then necessary. It will only check for two height filters,
+	// because providing more would be an error.
+	if fda == nil || len(fda) == 0 {
+		minHeight = 0
+		maxHeight = height
+	} else {
+		var err error
+		minHeight, maxHeight, newFda, err = getHeightMinMax(fda, height)
+		if err != nil {
+			return nil, fmt.Errorf("Error in query: " + err.Error())
+		}
+	}
+	blockMetas := make([]*types.BlockMeta, 0)
+	filter, skumtFel := this.filterFactory.NewFilter(newFda)
+	if skumtFel != nil {
+		return nil, fmt.Errorf("Fel i förfrågan. Helskumt...: " + skumtFel.Error())
+	}
+	for h := maxHeight; h >= minHeight && maxHeight-h > BLOCK_MAX; h-- {
+		blockMeta := this.blockStore.LoadBlockMeta(h)
+		if filter.Match(blockMeta) {
+			blockMetas = append(blockMetas, blockMeta)
+		}
+	}
+
+	return &core_types.Blocks{maxHeight, minHeight, blockMetas}, nil
+}
+
+// Get the block at height 'height'
+func (this *blockchain) Block(height int) (*types.Block, error) {
+	if height == 0 {
+		return nil, fmt.Errorf("height must be greater than 0")
+	}
+	if height > this.blockStore.Height() {
+		return nil, fmt.Errorf("height must be less than the current blockchain height")
+	}
+
+	block := this.blockStore.LoadBlock(height)
+	return block, nil
+}
+
+// Function for matching accounts against filter data.
+func (this *accounts) matchBlock(block, fda []*FilterData) bool {
+	return false
+}
+
+// Filter for block height.
+// Ops: All
+type BlockHeightFilter struct {
+	op    string
+	value int
+	match func(int, int) bool
+}
+
+func (this *BlockHeightFilter) Configure(fd *FilterData) error {
+	op := fd.Op
+	var val int
+	if fd.Value == "min" {
+		val = 0
+	} else if fd.Value == "max" {
+		val = math.MaxUint32
+	} else {
+		tv, err := strconv.ParseInt(fd.Value, 10, 0)
+		if err != nil {
+			return fmt.Errorf("Wrong value type.")
+		}
+		val = int(tv)
+	}
+
+	if op == "==" {
+		this.match = func(a, b int) bool {
+			return a == b
+		}
+	} else if op == "!=" {
+		this.match = func(a, b int) bool {
+			return a != b
+		}
+	} else if op == "<=" {
+		this.match = func(a, b int) bool {
+			return a <= b
+		}
+	} else if op == ">=" {
+		this.match = func(a, b int) bool {
+			return a >= b
+		}
+	} else if op == "<" {
+		this.match = func(a, b int) bool {
+			return a < b
+		}
+	} else if op == ">" {
+		this.match = func(a, b int) bool {
+			return a > b
+		}
+	} else {
+		return fmt.Errorf("Op: " + this.op + " is not supported for 'height' filtering")
+	}
+	this.op = op
+	this.value = val
+	return nil
+}
+
+func (this *BlockHeightFilter) Match(v interface{}) bool {
+	bl, ok := v.(*types.BlockMeta)
+	if !ok {
+		return false
+	}
+	return this.match(bl.Header.Height, this.value)
+}
+
+// TODO i should start using named return params...
+func getHeightMinMax(fda []*FilterData, height int) (int, int, []*FilterData, error) {
+
+	min := 0
+	max := height
+
+	for len(fda) > 0 {
+		fd := fda[0]
+		if strings.EqualFold(fd.Field, "height") {
+			var val int
+			if fd.Value == "min" {
+				val = 0
+			} else if fd.Value == "max" {
+				val = height
+			} else {
+				v, err := strconv.ParseInt(fd.Value, 10, 0)
+				if err != nil {
+					return 0, 0, nil, fmt.Errorf("Wrong value type")
+				}
+				val = int(v)
+			}
+			switch fd.Op {
+			case "==":
+				if val > height || val < 0 {
+					return 0, 0, nil, fmt.Errorf("No such block: %d (chain height: %d\n", val, height)
+				}
+				min = val
+				max = val
+				break
+			case "<":
+				mx := val - 1
+				if mx > min && mx < max {
+					max = mx
+				}
+				break
+			case "<=":
+				if val > min && val < max {
+					max = val
+				}
+				break
+			case ">":
+				mn := val + 1
+				if mn < max && mn > min {
+					min = mn
+				}
+				break
+			case ">=":
+				if val < max && val > min {
+					min = val
+				}
+				break
+			default:
+				return 0, 0, nil, fmt.Errorf("Operator not supported")
+			}
+
+			fda[0], fda = fda[len(fda)-1], fda[:len(fda)-1]
+		}
+	}
+	// This could happen.
+	if max < min {
+		max = min
+	}
+	return min, max, fda, nil
+}
+
+func min(x, y int) int {
+	if x > y {
+		return y
+	}
+	return x
+}
diff --git a/manager/eris-mint/consensus.go b/manager/eris-mint/consensus.go
new file mode 100644
index 00000000..21d4e18f
--- /dev/null
+++ b/manager/eris-mint/consensus.go
@@ -0,0 +1,65 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Consensus is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+
+package erismint
+import (
+	"github.com/tendermint/tendermint/types"
+
+  core_types "github.com/eris-ltd/eris-db/core/types"
+)
+
+// The consensus struct.
+type consensus struct {
+	erisMint *ErisMint
+}
+
+func newConsensus(erisMint *ErisMint) *consensus {
+	return &consensus{erisMint}
+}
+
+// Get the current consensus state.
+func (this *consensus) State() (*core_types.ConsensusState, error) {
+	// TODO-RPC!
+	return &core_types.ConsensusState{}, nil
+}
+
+// Get all validators.
+func (this *consensus) Validators() (*core_types.ValidatorList, error) {
+	var blockHeight int
+	bondedValidators := make([]*types.Validator, 0)
+	unbondingValidators := make([]*types.Validator, 0)
+
+	s := this.erisMint.GetState()
+	blockHeight = s.LastBlockHeight
+
+	// TODO: rpc
+
+	/*
+		s.BondedValidators.Iterate(func(index int, val *types.Validator) bool {
+			bondedValidators = append(bondedValidators, val)
+			return false
+		})
+		s.UnbondingValidators.Iterate(func(index int, val *types.Validator) bool {
+			unbondingValidators = append(unbondingValidators, val)
+			return false
+		})*/
+
+	return &core_types.ValidatorList{blockHeight, bondedValidators,
+    unbondingValidators}, nil
+}
diff --git a/manager/eris-mint/eris-mint.go b/manager/eris-mint/eris-mint.go
index a3e9c46d..4b351863 100644
--- a/manager/eris-mint/eris-mint.go
+++ b/manager/eris-mint/eris-mint.go
@@ -22,7 +22,7 @@ import (
   "fmt"
   "sync"
 
-  events "github.com/tendermint/go-events"
+  tendermint_events "github.com/tendermint/go-events"
   client "github.com/tendermint/go-rpc/client"
   wire   "github.com/tendermint/go-wire"
   ctypes "github.com/tendermint/tendermint/rpc/core/types"
@@ -47,8 +47,8 @@ type ErisMint struct {
   cache      *sm.BlockCache
   checkCache *sm.BlockCache // for CheckTx (eg. so we get nonces right)
 
-  evc  *events.EventCache
-  evsw *events.EventSwitch
+  evc  *tendermint_events.EventCache
+  evsw *tendermint_events.EventSwitch
 
   // client to the tendermint core rpc
   client *client.ClientURI
@@ -103,12 +103,12 @@ func (app *ErisMint) BroadcastTx(tx types.Tx) error {
   return err
 }
 
-func NewErisMint(s *sm.State, evsw *events.EventSwitch) *ErisMint {
+func NewErisMint(s *sm.State, evsw *tendermint_events.EventSwitch) *ErisMint {
   return &ErisMint{
     state:      s,
     cache:      sm.NewBlockCache(s),
     checkCache: sm.NewBlockCache(s),
-    evc:        events.NewEventCache(evsw),
+    evc:        tendermint_events.NewEventCache(evsw),
     evsw:       evsw,
   }
 }
diff --git a/manager/eris-mint/events.go b/manager/eris-mint/events.go
new file mode 100644
index 00000000..c7d582ae
--- /dev/null
+++ b/manager/eris-mint/events.go
@@ -0,0 +1,46 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Events is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+	evts "github.com/tendermint/go-events"
+)
+
+// TODO improve
+
+// The events struct has methods for working with events.
+type events struct {
+	eventSwitch *evts.EventSwitch
+}
+
+func newEvents(eventSwitch *evts.EventSwitch) *events {
+	return &events{eventSwitch}
+}
+
+// Subscribe to an event.
+func (this *events) Subscribe(subId, event string, callback func(evts.EventData)) (bool, error) {
+	this.eventSwitch.AddListenerForEvent(subId, event, callback)
+	return true, nil
+}
+
+// Un-subscribe from an event.
+func (this *events) Unsubscribe(subId string) (bool, error) {
+	this.eventSwitch.RemoveListener(subId)
+	return true, nil
+}
diff --git a/manager/eris-mint/filters.go b/manager/eris-mint/filters.go
new file mode 100644
index 00000000..49e72e65
--- /dev/null
+++ b/manager/eris-mint/filters.go
@@ -0,0 +1,210 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Filters is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+// TODO add generic filters for various different kinds of matching.
+
+// Used to filter.
+// Op can be any of the following:
+// The usual relative operators: <, >, <=, >=, ==, != (where applicable)
+// A range parameter (see: https://help.github.com/articles/search-syntax/)
+type FilterData struct {
+	Field string `json:"field"`
+	Op    string `json:"op"`
+	Value string `json:"value"`
+}
+
+// Filters based on fields.
+type Filter interface {
+	Match(v interface{}) bool
+}
+
+// A filter that can be configured with in-data.
+type ConfigurableFilter interface {
+	Filter
+	Configure(*FilterData) error
+}
+
+// Filter made up of many filters.
+type CompositeFilter struct {
+	filters []Filter
+}
+
+func (this *CompositeFilter) SetData(filters []Filter) {
+	this.filters = filters
+}
+
+func (this *CompositeFilter) Match(v interface{}) bool {
+	for _, f := range this.filters {
+		if !f.Match(v) {
+			return false
+		}
+	}
+	return true
+}
+
+// Rubberstamps everything.
+type MatchAllFilter struct{}
+
+func (this *MatchAllFilter) Match(v interface{}) bool { return true }
+
+// Used to generate filters based on filter data.
+// Keeping separate pools for "edge cases" (Composite and MatchAll)
+type FilterFactory struct {
+	filterPools         map[string]*sync.Pool
+	compositeFilterPool *sync.Pool
+	matchAllFilterPool  *sync.Pool
+}
+
+func NewFilterFactory() *FilterFactory {
+	aff := &FilterFactory{}
+	// Match all.
+	aff.matchAllFilterPool = &sync.Pool{
+		New: func() interface{} {
+			return &MatchAllFilter{}
+		},
+	}
+	// Composite.
+	aff.compositeFilterPool = &sync.Pool{
+		New: func() interface{} {
+			return &CompositeFilter{}
+		},
+	}
+	// Regular.
+	aff.filterPools = make(map[string]*sync.Pool)
+
+	return aff
+}
+
+func (this *FilterFactory) RegisterFilterPool(fieldName string, pool *sync.Pool) {
+	this.filterPools[strings.ToLower(fieldName)] = pool
+}
+
+// Creates a new filter given the input data array. If the array is zero length or nil, an empty
+// filter will be returned that returns true on all matches. If the array is of size 1, a regular
+// filter is returned, otherwise a CompositeFieldFilter is returned, which is a special filter that
+// contains a number of other filters. It implements AccountFieldFilter, and will match an account
+// only if all the sub-filters matches.
+func (this *FilterFactory) NewFilter(fdArr []*FilterData) (Filter, error) {
+
+	if fdArr == nil || len(fdArr) == 0 {
+		return &MatchAllFilter{}, nil
+	}
+	if len(fdArr) == 1 {
+		return this.newSingleFilter(fdArr[0])
+	}
+	filters := []Filter{}
+	for _, fd := range fdArr {
+		f, err := this.newSingleFilter(fd)
+		if err != nil {
+			return nil, err
+		}
+		filters = append(filters, f)
+	}
+	cf := this.compositeFilterPool.Get().(*CompositeFilter)
+	cf.filters = filters
+	return cf, nil
+}
+
+func (this *FilterFactory) newSingleFilter(fd *FilterData) (ConfigurableFilter, error) {
+	fp, ok := this.filterPools[strings.ToLower(fd.Field)]
+	if !ok {
+		return nil, fmt.Errorf("Field is not supported: " + fd.Field)
+	}
+	f := fp.Get().(ConfigurableFilter)
+	err := f.Configure(fd)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+// Some standard value parsing functions.
+
+func ParseNumberValue(value string) (int64, error) {
+	var val int64
+	// Check for wildcards.
+	if value == "min" {
+		val = math.MinInt64
+	} else if value == "max" {
+		val = math.MaxInt64
+	} else {
+		tv, err := strconv.ParseInt(value, 10, 64)
+
+		if err != nil {
+			return 0, fmt.Errorf("Wrong value type.")
+		}
+		val = tv
+	}
+	return val, nil
+}
+
+// Some standard filtering functions.
+
+func GetRangeFilter(op, fName string) (func(a, b int64) bool, error) {
+	if op == "==" {
+		return func(a, b int64) bool {
+			return a == b
+		}, nil
+	} else if op == "!=" {
+		return func(a, b int64) bool {
+			return a != b
+		}, nil
+	} else if op == "<=" {
+		return func(a, b int64) bool {
+			return a <= b
+		}, nil
+	} else if op == ">=" {
+		return func(a, b int64) bool {
+			return a >= b
+		}, nil
+	} else if op == "<" {
+		return func(a, b int64) bool {
+			return a < b
+		}, nil
+	} else if op == ">" {
+		return func(a, b int64) bool {
+			return a > b
+		}, nil
+	} else {
+		return nil, fmt.Errorf("Op: " + op + " is not supported for '" + fName + "' filtering")
+	}
+}
+
+func GetStringFilter(op, fName string) (func(s0, s1 string) bool, error) {
+	if op == "==" {
+		return func(s0, s1 string) bool {
+			return strings.EqualFold(s0, s1)
+		}, nil
+	} else if op == "!=" {
+		return func(s0, s1 string) bool {
+			return !strings.EqualFold(s0, s1)
+		}, nil
+	} else {
+		return nil, fmt.Errorf("Op: " + op + " is not supported for '" + fName + "' filtering.")
+	}
+}
diff --git a/manager/eris-mint/namereg.go b/manager/eris-mint/namereg.go
new file mode 100644
index 00000000..c54a4226
--- /dev/null
+++ b/manager/eris-mint/namereg.go
@@ -0,0 +1,241 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// NameReg is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"sync"
+
+	sm "github.com/eris-ltd/eris-db/manager/eris-mint/state"
+	"github.com/eris-ltd/eris-db/txs"
+)
+
+// The net struct.
+type namereg struct {
+	erisMint      *ErisMint
+	filterFactory *FilterFactory
+}
+
+func newNamereg(erisMint *ErisMint) *namereg {
+
+	ff := NewFilterFactory()
+
+	ff.RegisterFilterPool("name", &sync.Pool{
+		New: func() interface{} {
+			return &NameRegNameFilter{}
+		},
+	})
+
+	ff.RegisterFilterPool("owner", &sync.Pool{
+		New: func() interface{} {
+			return &NameRegOwnerFilter{}
+		},
+	})
+
+	ff.RegisterFilterPool("data", &sync.Pool{
+		New: func() interface{} {
+			return &NameRegDataFilter{}
+		},
+	})
+
+	ff.RegisterFilterPool("expires", &sync.Pool{
+		New: func() interface{} {
+			return &NameRegExpiresFilter{}
+		},
+	})
+
+	return &namereg{erisMint, ff}
+}
+
+func (this *namereg) Entry(key string) (*txs.NameRegEntry, error) {
+	st := this.erisMint.GetState() // performs a copy
+	entry := st.GetNameRegEntry(key)
+	if entry == nil {
+		return nil, fmt.Errorf("Entry %s not found", key)
+	}
+	return entry, nil
+}
+
+func (this *namereg) Entries(filters []*FilterData) (*ResultListNames, error) {
+	var blockHeight int
+	var names []*txs.NameRegEntry
+	state := this.erisMint.GetState()
+	blockHeight = state.LastBlockHeight
+	filter, err := this.filterFactory.NewFilter(filters)
+	if err != nil {
+		return nil, fmt.Errorf("Error in query: " + err.Error())
+	}
+	state.GetNames().Iterate(func(key, value []byte) bool {
+		nre := sm.DecodeNameRegEntry(value)
+		if filter.Match(nre) {
+			names = append(names, nre)
+		}
+		return false
+	})
+	return &ResultListNames{blockHeight, names}, nil
+}
+
+type ResultListNames struct {
+	BlockHeight int                 `json:"block_height"`
+	Names       []*txs.NameRegEntry `json:"names"`
+}
+
+// Filter for namereg name. This should not be used to get individual entries by name.
+// Ops: == or !=
+type NameRegNameFilter struct {
+	op    string
+	value string
+	match func(string, string) bool
+}
+
+func (this *NameRegNameFilter) Configure(fd *FilterData) error {
+	op := fd.Op
+	val := fd.Value
+
+	if op == "==" {
+		this.match = func(a, b string) bool {
+			return a == b
+		}
+	} else if op == "!=" {
+		this.match = func(a, b string) bool {
+			return a != b
+		}
+	} else {
+		return fmt.Errorf("Op: " + this.op + " is not supported for 'name' filtering")
+	}
+	this.op = op
+	this.value = val
+	return nil
+}
+
+func (this *NameRegNameFilter) Match(v interface{}) bool {
+	nre, ok := v.(*txs.NameRegEntry)
+	if !ok {
+		return false
+	}
+	return this.match(nre.Name, this.value)
+}
+
+// Filter for owner.
+// Ops: == or !=
+type NameRegOwnerFilter struct {
+	op    string
+	value []byte
+	match func([]byte, []byte) bool
+}
+
+func (this *NameRegOwnerFilter) Configure(fd *FilterData) error {
+	op := fd.Op
+	val, err := hex.DecodeString(fd.Value)
+
+	if err != nil {
+		return fmt.Errorf("Wrong value type.")
+	}
+	if op == "==" {
+		this.match = func(a, b []byte) bool {
+			return bytes.Equal(a, b)
+		}
+	} else if op == "!=" {
+		this.match = func(a, b []byte) bool {
+			return !bytes.Equal(a, b)
+		}
+	} else {
+		return fmt.Errorf("Op: " + this.op + " is not supported for 'owner' filtering")
+	}
+	this.op = op
+	this.value = val
+	return nil
+}
+
+func (this *NameRegOwnerFilter) Match(v interface{}) bool {
+	nre, ok := v.(*txs.NameRegEntry)
+	if !ok {
+		return false
+	}
+	return this.match(nre.Owner, this.value)
+}
+
+// Filter for namereg data. Useful for example if you store an ipfs hash and know the hash but need the key.
+// Ops: == or !=
+type NameRegDataFilter struct {
+	op    string
+	value string
+	match func(string, string) bool
+}
+
+func (this *NameRegDataFilter) Configure(fd *FilterData) error {
+	op := fd.Op
+	val := fd.Value
+
+	if op == "==" {
+		this.match = func(a, b string) bool {
+			return a == b
+		}
+	} else if op == "!=" {
+		this.match = func(a, b string) bool {
+			return a != b
+		}
+	} else {
+		return fmt.Errorf("Op: " + this.op + " is not supported for 'data' filtering")
+	}
+	this.op = op
+	this.value = val
+	return nil
+}
+
+func (this *NameRegDataFilter) Match(v interface{}) bool {
+	nre, ok := v.(*txs.NameRegEntry)
+	if !ok {
+		return false
+	}
+	return this.match(nre.Data, this.value)
+}
+
+// Filter for expires.
+// Ops: All
+type NameRegExpiresFilter struct {
+	op    string
+	value int64
+	match func(int64, int64) bool
+}
+
+func (this *NameRegExpiresFilter) Configure(fd *FilterData) error {
+	val, err := ParseNumberValue(fd.Value)
+	if err != nil {
+		return err
+	}
+	match, err2 := GetRangeFilter(fd.Op, "expires")
+	if err2 != nil {
+		return err2
+	}
+	this.match = match
+	this.op = fd.Op
+	this.value = val
+	return nil
+}
+
+func (this *NameRegExpiresFilter) Match(v interface{}) bool {
+	nre, ok := v.(*txs.NameRegEntry)
+	if !ok {
+		return false
+	}
+	return this.match(int64(nre.Expires), this.value)
+}
diff --git a/manager/eris-mint/net.go b/manager/eris-mint/net.go
new file mode 100644
index 00000000..d8677155
--- /dev/null
+++ b/manager/eris-mint/net.go
@@ -0,0 +1,70 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Net is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+  core_types "github.com/eris-ltd/eris-db/core/types"
+)
+
+// TODO-RPC!
+
+// The net struct.
+type network struct {
+}
+
+func newNetwork() *network {
+	return &network{}
+}
+
+//-----------------------------------------------------------------------------
+
+// Get the complete net info.
+func (this *network) Info() (*core_types.NetworkInfo, error) {
+	return &core_types.NetworkInfo{}, nil
+}
+
+// Get the client version
+func (this *network) ClientVersion() (string, error) {
+	return "not-fully-loaded-yet", nil
+}
+
+// Get the moniker
+func (this *network) Moniker() (string, error) {
+	return "rekinom", nil
+}
+
+// Is the network currently listening for connections.
+func (this *network) Listening() (bool, error) {
+	return false, nil
+}
+
+// Is the network currently listening for connections.
+func (this *network) Listeners() ([]string, error) {
+	return []string{}, nil
+}
+
+// Get a list of all peers.
+func (this *network) Peers() ([]*core_types.Peer, error) {
+	return []*core_types.Peer{}, nil
+}
+
+// Get a peer. TODO Need to do something about the address.
+func (this *network) Peer(address string) (*core_types.Peer, error) {
+	return &core_types.Peer{}, nil
+}
diff --git a/manager/eris-mint/pipe.go b/manager/eris-mint/pipe.go
index edfe3163..08e3000b 100644
--- a/manager/eris-mint/pipe.go
+++ b/manager/eris-mint/pipe.go
@@ -21,7 +21,7 @@ import (
   "fmt"
 
   db     "github.com/tendermint/go-db"
-  events "github.com/tendermint/go-events"
+  tendermint_events "github.com/tendermint/go-events"
   wire   "github.com/tendermint/go-wire"
 
   log "github.com/eris-ltd/eris-logger"
@@ -33,12 +33,12 @@ import (
 
 type ErisMintPipe struct {
   erisMintState *state.State
-  eventSwitch   *events.EventSwitch
+  eventSwitch   *tendermint_events.EventSwitch
   erisMint      *ErisMint
 }
 
 func NewErisMintPipe(moduleConfig *config.ModuleConfig,
-  genesisFile string, eventSwitch *events.EventSwitch) (*ErisMintPipe, error) {
+  genesisFile string, eventSwitch *tendermint_events.EventSwitch) (*ErisMintPipe, error) {
 
   startedState, err := startState(moduleConfig.DataDir,
     moduleConfig.Config.GetString("db_backend"), genesisFile,
@@ -110,3 +110,6 @@ func startState(dataDir, backend, genesisFile, chainId string) (*state.State,
 
   return newState, nil
 }
+
+//------------------------------------------------------------------------------
+// Implement definitions.Pipe for ErisMintPipe
diff --git a/manager/eris-mint/transactor.go b/manager/eris-mint/transactor.go
new file mode 100644
index 00000000..54837514
--- /dev/null
+++ b/manager/eris-mint/transactor.go
@@ -0,0 +1,323 @@
+// Copyright 2015, 2016 Eris Industries (UK) Ltd.
+// This file is part of Eris-RT
+
+// Eris-RT is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Eris-RT 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 General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Eris-RT.  If not, see <http://www.gnu.org/licenses/>.
+
+// Transactor is part of the pipe for ErisMint and provides the implementation
+// for the pipe to call into the ErisMint application
+package erismint
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"sync"
+	"time"
+
+	cmn "github.com/tendermint/go-common"
+	"github.com/tendermint/go-crypto"
+	tEvents "github.com/tendermint/go-events"
+
+  "github.com/eris-ltd/eris-db/account"
+  core_types  "github.com/eris-ltd/eris-db/core/types"
+  definitions "github.com/eris-ltd/eris-db/definitions"
+  "github.com/eris-ltd/eris-db/manager/eris-mint/evm"
+  "github.com/eris-ltd/eris-db/manager/eris-mint/state"
+  "github.com/eris-ltd/eris-db/txs"
+)
+
+type transactor struct {
+	chainID      string
+	eventSwitch  tEvents.Fireable
+	erisMint     *ErisMint
+	eventEmitter definitions.EventEmitter
+	txMtx        *sync.Mutex
+}
+
+func newTransactor(chainID string, eventSwitch tEvents.Fireable,
+	erisMint *ErisMint, eventEmitter definitions.EventEmitter) *transactor {
+	txs := &transactor{
+		chainID,
+		eventSwitch,
+		erisMint,
+		eventEmitter,
+		&sync.Mutex{},
+	}
+	return txs
+}
+
+// Run a contract's code on an isolated and unpersisted state
+// Cannot be used to create new contracts
+func (this *transactor) Call(fromAddress, toAddress, data []byte) (
+  *core_types.Call, error) {
+
+	cache := this.erisMint.GetCheckCache() // XXX: DON'T MUTATE THIS CACHE (used internally for CheckTx)
+	outAcc := cache.GetAccount(toAddress)
+	if outAcc == nil {
+		return nil, fmt.Errorf("Account %X does not exist", toAddress)
+	}
+	if fromAddress == nil {
+		fromAddress = []byte{}
+	}
+	callee := toVMAccount(outAcc)
+	caller := &vm.Account{Address: cmn.LeftPadWord256(fromAddress)}
+	txCache := state.NewTxCache(cache)
+	st := this.erisMint.GetState() // for block height, time
+	params := vm.Params{
+		BlockHeight: int64(st.LastBlockHeight),
+		BlockHash:   cmn.LeftPadWord256(st.LastBlockHash),
+		BlockTime:   st.LastBlockTime.Unix(),
+		GasLimit:    10000000,
+	}
+
+	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	vmach.SetFireable(this.eventSwitch)
+	gas := int64(1000000000)
+	ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
+	if err != nil {
+		return nil, err
+	}
+	return &core_types.Call{Return: hex.EncodeToString(ret)}, nil
+}
+
+// Run the given code on an isolated and unpersisted state
+// Cannot be used to create new contracts.
+func (this *transactor) CallCode(fromAddress, code, data []byte) (
+  *core_types.Call, error) {
+	if fromAddress == nil {
+		fromAddress = []byte{}
+	}
+	cache := this.erisMint.GetCheckCache() // XXX: DON'T MUTATE THIS CACHE (used internally for CheckTx)
+	callee := &vm.Account{Address: cmn.LeftPadWord256(fromAddress)}
+	caller := &vm.Account{Address: cmn.LeftPadWord256(fromAddress)}
+	txCache := state.NewTxCache(cache)
+	st := this.erisMint.GetState() // for block height, time
+	params := vm.Params{
+		BlockHeight: int64(st.LastBlockHeight),
+		BlockHash:   cmn.LeftPadWord256(st.LastBlockHash),
+		BlockTime:   st.LastBlockTime.Unix(),
+		GasLimit:    10000000,
+	}
+
+	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	gas := int64(1000000000)
+	ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
+	if err != nil {
+		return nil, err
+	}
+	return &core_types.Call{Return: hex.EncodeToString(ret)}, nil
+}
+
+// Broadcast a transaction.
+func (this *transactor) BroadcastTx(tx txs.Tx) (*core_types.Receipt, error) {
+
+	err := this.erisMint.BroadcastTx(tx)
+	if err != nil {
+		return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
+	}
+
+	txHash := txs.TxID(this.chainID, tx)
+	var createsContract uint8
+	var contractAddr []byte
+	// check if creates new contract
+	if callTx, ok := tx.(*txs.CallTx); ok {
+		if len(callTx.Address) == 0 {
+			createsContract = 1
+			contractAddr = state.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence)
+		}
+	}
+	return &core_types.Receipt{txHash, createsContract, contractAddr}, nil
+}
+
+// Get all unconfirmed txs.
+func (this *transactor) UnconfirmedTxs() (*core_types.UnconfirmedTxs, error) {
+	// TODO-RPC
+	return &core_types.UnconfirmedTxs{}, nil
+}
+
+// Orders calls to BroadcastTx using lock (waits for response from core before releasing)
+func (this *transactor) Transact(privKey, address, data []byte, gasLimit,
+  fee int64) (*core_types.Receipt, error) {
+	var addr []byte
+	if len(address) == 0 {
+		addr = nil
+	} else if len(address) != 20 {
+		return nil, fmt.Errorf("Address is not of the right length: %d\n", len(address))
+	} else {
+		addr = address
+	}
+	if len(privKey) != 64 {
+		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey))
+	}
+	this.txMtx.Lock()
+	defer this.txMtx.Unlock()
+	pa := account.GenPrivAccountFromPrivKeyBytes(privKey)
+	cache := this.erisMint.GetCheckCache() // XXX: DON'T MUTATE THIS CACHE (used internally for CheckTx)
+	acc := cache.GetAccount(pa.Address)
+	var sequence int
+	if acc == nil {
+		sequence = 1
+	} else {
+		sequence = acc.Sequence + 1
+	}
+	// fmt.Printf("Sequence %d\n", sequence)
+	txInput := &txs.TxInput{
+		Address:  pa.Address,
+		Amount:   1,
+		Sequence: sequence,
+		PubKey:   pa.PubKey,
+	}
+	tx := &txs.CallTx{
+		Input:    txInput,
+		Address:  addr,
+		GasLimit: gasLimit,
+		Fee:      fee,
+		Data:     data,
+	}
+
+	// Got ourselves a tx.
+	txS, errS := this.SignTx(tx, []*account.PrivAccount{pa})
+	if errS != nil {
+		return nil, errS
+	}
+	return this.BroadcastTx(txS)
+}
+
+func (this *transactor) TransactAndHold(privKey, address, data []byte, gasLimit, fee int64) (*txs.EventDataCall, error) {
+	rec, tErr := this.Transact(privKey, address, data, gasLimit, fee)
+	if tErr != nil {
+		return nil, tErr
+	}
+	var addr []byte
+	if rec.CreatesContract == 1 {
+		addr = rec.ContractAddr
+	} else {
+		addr = address
+	}
+	wc := make(chan *txs.EventDataCall)
+	subId := fmt.Sprintf("%X", rec.TxHash)
+	this.eventEmitter.Subscribe(subId, txs.EventStringAccCall(addr), func(evt tEvents.EventData) {
+		event := evt.(txs.EventDataCall)
+		if bytes.Equal(event.TxID, rec.TxHash) {
+			wc <- &event
+		}
+	})
+
+	timer := time.NewTimer(300 * time.Second)
+	toChan := timer.C
+
+	var ret *txs.EventDataCall
+	var rErr error
+
+	select {
+	case <-toChan:
+		rErr = fmt.Errorf("Transaction timed out. Hash: " + subId)
+	case e := <-wc:
+		timer.Stop()
+		if e.Exception != "" {
+			rErr = fmt.Errorf("Error when transacting: " + e.Exception)
+		} else {
+			ret = e
+		}
+	}
+	this.eventEmitter.Unsubscribe(subId)
+	return ret, rErr
+}
+
+func (this *transactor) TransactNameReg(privKey []byte, name, data string,
+  amount, fee int64) (*core_types.Receipt, error) {
+
+	if len(privKey) != 64 {
+		return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey))
+	}
+	this.txMtx.Lock()
+	defer this.txMtx.Unlock()
+	pa := account.GenPrivAccountFromPrivKeyBytes(privKey)
+	cache := this.erisMint.GetCheckCache() // XXX: DON'T MUTATE THIS CACHE (used internally for CheckTx)
+	acc := cache.GetAccount(pa.Address)
+	var sequence int
+	if acc == nil {
+		sequence = 1
+	} else {
+		sequence = acc.Sequence + 1
+	}
+	tx := txs.NewNameTxWithNonce(pa.PubKey, name, data, amount, fee, sequence)
+	// Got ourselves a tx.
+	txS, errS := this.SignTx(tx, []*account.PrivAccount{pa})
+	if errS != nil {
+		return nil, errS
+	}
+	return this.BroadcastTx(txS)
+}
+
+// Sign a transaction
+func (this *transactor) SignTx(tx txs.Tx, privAccounts []*account.PrivAccount) (txs.Tx, error) {
+	// more checks?
+
+	for i, privAccount := range privAccounts {
+		if privAccount == nil || privAccount.PrivKey == nil {
+			return nil, fmt.Errorf("Invalid (empty) privAccount @%v", i)
+		}
+	}
+	switch tx.(type) {
+	case *txs.NameTx:
+		nameTx := tx.(*txs.NameTx)
+		nameTx.Input.PubKey = privAccounts[0].PubKey
+		nameTx.Input.Signature = privAccounts[0].Sign(this.chainID, nameTx)
+	case *txs.SendTx:
+		sendTx := tx.(*txs.SendTx)
+		for i, input := range sendTx.Inputs {
+			input.PubKey = privAccounts[i].PubKey
+			input.Signature = privAccounts[i].Sign(this.chainID, sendTx)
+		}
+		break
+	case *txs.CallTx:
+		callTx := tx.(*txs.CallTx)
+		callTx.Input.PubKey = privAccounts[0].PubKey
+		callTx.Input.Signature = privAccounts[0].Sign(this.chainID, callTx)
+		break
+	case *txs.BondTx:
+		bondTx := tx.(*txs.BondTx)
+		// the first privaccount corresponds to the BondTx pub key.
+		// the rest to the inputs
+		bondTx.Signature = privAccounts[0].Sign(this.chainID, bondTx).(crypto.SignatureEd25519)
+		for i, input := range bondTx.Inputs {
+			input.PubKey = privAccounts[i+1].PubKey
+			input.Signature = privAccounts[i+1].Sign(this.chainID, bondTx)
+		}
+		break
+	case *txs.UnbondTx:
+		unbondTx := tx.(*txs.UnbondTx)
+		unbondTx.Signature = privAccounts[0].Sign(this.chainID, unbondTx).(crypto.SignatureEd25519)
+		break
+	case *txs.RebondTx:
+		rebondTx := tx.(*txs.RebondTx)
+		rebondTx.Signature = privAccounts[0].Sign(this.chainID, rebondTx).(crypto.SignatureEd25519)
+		break
+	default:
+		return nil, fmt.Errorf("Object is not a proper transaction: %v\n", tx)
+	}
+	return tx, nil
+}
+
+// No idea what this does.
+func toVMAccount(acc *account.Account) *vm.Account {
+	return &vm.Account{
+		Address: cmn.LeftPadWord256(acc.Address),
+		Balance: acc.Balance,
+		Code:    acc.Code,
+		Nonce:   int64(acc.Sequence),
+		Other:   acc.PubKey,
+	}
+}
-- 
GitLab