diff options
author | Jeffrey Wilcke <obscuren@users.noreply.github.com> | 2014-10-23 22:46:18 +0800 |
---|---|---|
committer | Jeffrey Wilcke <obscuren@users.noreply.github.com> | 2014-10-23 22:46:18 +0800 |
commit | 119c5b40a7ed1aea1c871c0cb56956b8ef9303d9 (patch) | |
tree | b021423da04c9ff319a77549b473b6bad4930dd4 /ethpipe | |
parent | 50fd46924900869e7210217c6a07979b544991c8 (diff) | |
parent | 184055b3e2995894ccaba364484223e488730627 (diff) | |
download | dexon-119c5b40a7ed1aea1c871c0cb56956b8ef9303d9.tar.gz dexon-119c5b40a7ed1aea1c871c0cb56956b8ef9303d9.tar.zst dexon-119c5b40a7ed1aea1c871c0cb56956b8ef9303d9.zip |
Merge pull request #150 from fjl/develop
Merge eth-go repo into go-ethereum
Diffstat (limited to 'ethpipe')
-rw-r--r-- | ethpipe/config.go | 33 | ||||
-rw-r--r-- | ethpipe/js_pipe.go | 264 | ||||
-rw-r--r-- | ethpipe/js_types.go | 222 | ||||
-rw-r--r-- | ethpipe/object.go | 26 | ||||
-rw-r--r-- | ethpipe/pipe.go | 171 | ||||
-rw-r--r-- | ethpipe/pipe_test.go | 58 | ||||
-rw-r--r-- | ethpipe/vm_env.go | 39 | ||||
-rw-r--r-- | ethpipe/world.go | 64 |
8 files changed, 877 insertions, 0 deletions
diff --git a/ethpipe/config.go b/ethpipe/config.go new file mode 100644 index 000000000..bea5005b6 --- /dev/null +++ b/ethpipe/config.go @@ -0,0 +1,33 @@ +package ethpipe + +import "github.com/ethereum/go-ethereum/ethutil" + +var cnfCtr = ethutil.Hex2Bytes("661005d2720d855f1d9976f88bb10c1a3398c77f") + +type Config struct { + pipe *Pipe +} + +func (self *Config) Get(name string) *Object { + configCtrl := self.pipe.World().safeGet(cnfCtr) + var addr []byte + + switch name { + case "NameReg": + addr = []byte{0} + case "DnsReg": + objectAddr := configCtrl.GetStorage(ethutil.BigD([]byte{0})) + domainAddr := (&Object{self.pipe.World().safeGet(objectAddr.Bytes())}).StorageString("DnsReg").Bytes() + return &Object{self.pipe.World().safeGet(domainAddr)} + default: + addr = ethutil.RightPadBytes([]byte(name), 32) + } + + objectAddr := configCtrl.GetStorage(ethutil.BigD(addr)) + + return &Object{self.pipe.World().safeGet(objectAddr.Bytes())} +} + +func (self *Config) Exist() bool { + return self.pipe.World().Get(cnfCtr) != nil +} diff --git a/ethpipe/js_pipe.go b/ethpipe/js_pipe.go new file mode 100644 index 000000000..4b4369768 --- /dev/null +++ b/ethpipe/js_pipe.go @@ -0,0 +1,264 @@ +package ethpipe + +import ( + "bytes" + "encoding/json" + "sync/atomic" + + "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" +) + +type JSPipe struct { + *Pipe +} + +func NewJSPipe(eth ethchain.EthManager) *JSPipe { + return &JSPipe{New(eth)} +} + +func (self *JSPipe) BlockByHash(strHash string) *JSBlock { + hash := ethutil.Hex2Bytes(strHash) + block := self.obj.ChainManager().GetBlock(hash) + + return NewJSBlock(block) +} + +func (self *JSPipe) BlockByNumber(num int32) *JSBlock { + if num == -1 { + return NewJSBlock(self.obj.ChainManager().CurrentBlock) + } + + return NewJSBlock(self.obj.ChainManager().GetBlockByNumber(uint64(num))) +} + +func (self *JSPipe) Block(v interface{}) *JSBlock { + if n, ok := v.(int32); ok { + return self.BlockByNumber(n) + } else if str, ok := v.(string); ok { + return self.BlockByHash(str) + } else if f, ok := v.(float64); ok { // Don't ask ... + return self.BlockByNumber(int32(f)) + } + + return nil +} + +func (self *JSPipe) Key() *JSKey { + return NewJSKey(self.obj.KeyManager().KeyPair()) +} + +func (self *JSPipe) StateObject(addr string) *JSObject { + object := &Object{self.World().safeGet(ethutil.Hex2Bytes(addr))} + + return NewJSObject(object) +} + +func (self *JSPipe) PeerCount() int { + return self.obj.PeerCount() +} + +func (self *JSPipe) Peers() []JSPeer { + var peers []JSPeer + for peer := self.obj.Peers().Front(); peer != nil; peer = peer.Next() { + p := peer.Value.(ethchain.Peer) + // we only want connected peers + if atomic.LoadInt32(p.Connected()) != 0 { + peers = append(peers, *NewJSPeer(p)) + } + } + + return peers +} + +func (self *JSPipe) IsMining() bool { + return self.obj.IsMining() +} + +func (self *JSPipe) IsListening() bool { + return self.obj.IsListening() +} + +func (self *JSPipe) CoinBase() string { + return ethutil.Bytes2Hex(self.obj.KeyManager().Address()) +} + +func (self *JSPipe) NumberToHuman(balance string) string { + b := ethutil.Big(balance) + + return ethutil.CurrencyToString(b) +} + +func (self *JSPipe) StorageAt(addr, storageAddr string) string { + storage := self.World().SafeGet(ethutil.Hex2Bytes(addr)).Storage(ethutil.Hex2Bytes(storageAddr)) + + return ethutil.Bytes2Hex(storage.Bytes()) +} + +func (self *JSPipe) BalanceAt(addr string) string { + return self.World().SafeGet(ethutil.Hex2Bytes(addr)).Balance().String() +} + +func (self *JSPipe) TxCountAt(address string) int { + return int(self.World().SafeGet(ethutil.Hex2Bytes(address)).Nonce) +} + +func (self *JSPipe) CodeAt(address string) string { + return ethutil.Bytes2Hex(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) +} + +func (self *JSPipe) IsContract(address string) bool { + return len(self.World().SafeGet(ethutil.Hex2Bytes(address)).Code) > 0 +} + +func (self *JSPipe) SecretToAddress(key string) string { + pair, err := ethcrypto.NewKeyPairFromSec(ethutil.Hex2Bytes(key)) + if err != nil { + return "" + } + + return ethutil.Bytes2Hex(pair.Address()) +} + +func (self *JSPipe) Execute(addr, value, gas, price, data string) (string, error) { + ret, err := self.ExecuteObject(&Object{ + self.World().safeGet(ethutil.Hex2Bytes(addr))}, + ethutil.Hex2Bytes(data), + ethutil.NewValue(value), + ethutil.NewValue(gas), + ethutil.NewValue(price), + ) + + return ethutil.Bytes2Hex(ret), err +} + +type KeyVal struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (self *JSPipe) EachStorage(addr string) string { + var values []KeyVal + object := self.World().SafeGet(ethutil.Hex2Bytes(addr)) + object.EachStorage(func(name string, value *ethutil.Value) { + value.Decode() + values = append(values, KeyVal{ethutil.Bytes2Hex([]byte(name)), ethutil.Bytes2Hex(value.Bytes())}) + }) + + valuesJson, err := json.Marshal(values) + if err != nil { + return "" + } + + return string(valuesJson) +} + +func (self *JSPipe) ToAscii(str string) string { + padded := ethutil.RightPadBytes([]byte(str), 32) + + return "0x" + ethutil.Bytes2Hex(padded) +} + +func (self *JSPipe) FromAscii(str string) string { + if ethutil.IsHex(str) { + str = str[2:] + } + + return string(bytes.Trim(ethutil.Hex2Bytes(str), "\x00")) +} + +func (self *JSPipe) FromNumber(str string) string { + if ethutil.IsHex(str) { + str = str[2:] + } + + return ethutil.BigD(ethutil.Hex2Bytes(str)).String() +} + +func (self *JSPipe) Transact(key, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (*JSReceipt, error) { + var hash []byte + var contractCreation bool + if len(toStr) == 0 { + contractCreation = true + } else { + // Check if an address is stored by this address + addr := self.World().Config().Get("NameReg").StorageString(toStr).Bytes() + if len(addr) > 0 { + hash = addr + } else { + hash = ethutil.Hex2Bytes(toStr) + } + } + + var keyPair *ethcrypto.KeyPair + var err error + if ethutil.IsHex(key) { + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key[2:]))) + } else { + keyPair, err = ethcrypto.NewKeyPairFromSec([]byte(ethutil.Hex2Bytes(key))) + } + + if err != nil { + return nil, err + } + + var ( + value = ethutil.Big(valueStr) + gas = ethutil.Big(gasStr) + gasPrice = ethutil.Big(gasPriceStr) + data []byte + tx *ethchain.Transaction + ) + + if ethutil.IsHex(codeStr) { + data = ethutil.Hex2Bytes(codeStr[2:]) + } else { + data = ethutil.Hex2Bytes(codeStr) + } + + if contractCreation { + tx = ethchain.NewContractCreationTx(value, gas, gasPrice, data) + } else { + tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, data) + } + + acc := self.obj.StateManager().TransState().GetOrNewStateObject(keyPair.Address()) + tx.Nonce = acc.Nonce + acc.Nonce += 1 + self.obj.StateManager().TransState().UpdateStateObject(acc) + + tx.Sign(keyPair.PrivateKey) + self.obj.TxPool().QueueTransaction(tx) + + if contractCreation { + logger.Infof("Contract addr %x", tx.CreationAddress(self.World().State())) + } + + return NewJSReciept(contractCreation, tx.CreationAddress(self.World().State()), tx.Hash(), keyPair.Address()), nil +} + +func (self *JSPipe) PushTx(txStr string) (*JSReceipt, error) { + tx := ethchain.NewTransactionFromBytes(ethutil.Hex2Bytes(txStr)) + self.obj.TxPool().QueueTransaction(tx) + return NewJSReciept(tx.CreatesContract(), tx.CreationAddress(self.World().State()), tx.Hash(), tx.Sender()), nil +} + +func (self *JSPipe) CompileMutan(code string) string { + data, err := self.Pipe.CompileMutan(code) + if err != nil { + return err.Error() + } + + return ethutil.Bytes2Hex(data) +} + +func ToJSMessages(messages ethstate.Messages) *ethutil.List { + var msgs []JSMessage + for _, m := range messages { + msgs = append(msgs, NewJSMessage(m)) + } + + return ethutil.NewList(msgs) +} diff --git a/ethpipe/js_types.go b/ethpipe/js_types.go new file mode 100644 index 000000000..05c12fbf6 --- /dev/null +++ b/ethpipe/js_types.go @@ -0,0 +1,222 @@ +package ethpipe + +import ( + "fmt" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" +) + +// Block interface exposed to QML +type JSBlock struct { + //Transactions string `json:"transactions"` + ref *ethchain.Block + Size string `json:"size"` + Number int `json:"number"` + Hash string `json:"hash"` + Transactions *ethutil.List `json:"transactions"` + Time int64 `json:"time"` + Coinbase string `json:"coinbase"` + Name string `json:"name"` + GasLimit string `json:"gasLimit"` + GasUsed string `json:"gasUsed"` + PrevHash string `json:"prevHash"` +} + +// Creates a new QML Block from a chain block +func NewJSBlock(block *ethchain.Block) *JSBlock { + if block == nil { + return &JSBlock{} + } + + var ptxs []*JSTransaction + for _, tx := range block.Transactions() { + ptxs = append(ptxs, NewJSTx(tx, block.State())) + } + + list := ethutil.NewList(ptxs) + + return &JSBlock{ + ref: block, Size: block.Size().String(), + Number: int(block.Number.Uint64()), GasUsed: block.GasUsed.String(), + GasLimit: block.GasLimit.String(), Hash: ethutil.Bytes2Hex(block.Hash()), + Transactions: list, Time: block.Time, + Coinbase: ethutil.Bytes2Hex(block.Coinbase), + PrevHash: ethutil.Bytes2Hex(block.PrevHash), + } +} + +func (self *JSBlock) ToString() string { + if self.ref != nil { + return self.ref.String() + } + + return "" +} + +func (self *JSBlock) GetTransaction(hash string) *JSTransaction { + tx := self.ref.GetTransaction(ethutil.Hex2Bytes(hash)) + if tx == nil { + return nil + } + + return NewJSTx(tx, self.ref.State()) +} + +type JSTransaction struct { + ref *ethchain.Transaction + + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Hash string `json:"hash"` + Address string `json:"address"` + Sender string `json:"sender"` + RawData string `json:"rawData"` + Data string `json:"data"` + Contract bool `json:"isContract"` + CreatesContract bool `json:"createsContract"` + Confirmations int `json:"confirmations"` +} + +func NewJSTx(tx *ethchain.Transaction, state *ethstate.State) *JSTransaction { + hash := ethutil.Bytes2Hex(tx.Hash()) + receiver := ethutil.Bytes2Hex(tx.Recipient) + if receiver == "0000000000000000000000000000000000000000" { + receiver = ethutil.Bytes2Hex(tx.CreationAddress(state)) + } + sender := ethutil.Bytes2Hex(tx.Sender()) + createsContract := tx.CreatesContract() + + var data string + if tx.CreatesContract() { + data = strings.Join(ethchain.Disassemble(tx.Data), "\n") + } else { + data = ethutil.Bytes2Hex(tx.Data) + } + + return &JSTransaction{ref: tx, Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: receiver, Contract: tx.CreatesContract(), Gas: tx.Gas.String(), GasPrice: tx.GasPrice.String(), Data: data, Sender: sender, CreatesContract: createsContract, RawData: ethutil.Bytes2Hex(tx.Data)} +} + +func (self *JSTransaction) ToString() string { + return self.ref.String() +} + +type JSKey struct { + Address string `json:"address"` + PrivateKey string `json:"privateKey"` + PublicKey string `json:"publicKey"` +} + +func NewJSKey(key *ethcrypto.KeyPair) *JSKey { + return &JSKey{ethutil.Bytes2Hex(key.Address()), ethutil.Bytes2Hex(key.PrivateKey), ethutil.Bytes2Hex(key.PublicKey)} +} + +type JSObject struct { + *Object +} + +func NewJSObject(object *Object) *JSObject { + return &JSObject{object} +} + +type PReceipt struct { + CreatedContract bool `json:"createdContract"` + Address string `json:"address"` + Hash string `json:"hash"` + Sender string `json:"sender"` +} + +func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *PReceipt { + return &PReceipt{ + contractCreation, + ethutil.Bytes2Hex(creationAddress), + ethutil.Bytes2Hex(hash), + ethutil.Bytes2Hex(address), + } +} + +// Peer interface exposed to QML + +type JSPeer struct { + ref *ethchain.Peer + Inbound bool `json:"isInbound"` + LastSend int64 `json:"lastSend"` + LastPong int64 `json:"lastPong"` + Ip string `json:"ip"` + Port int `json:"port"` + Version string `json:"version"` + LastResponse string `json:"lastResponse"` + Latency string `json:"latency"` + Caps string `json:"caps"` +} + +func NewJSPeer(peer ethchain.Peer) *JSPeer { + if peer == nil { + return nil + } + + var ip []string + for _, i := range peer.Host() { + ip = append(ip, strconv.Itoa(int(i))) + } + ipAddress := strings.Join(ip, ".") + + var caps []string + capsIt := peer.Caps().NewIterator() + for capsIt.Next() { + caps = append(caps, capsIt.Value().Str()) + } + + return &JSPeer{ref: &peer, Inbound: peer.Inbound(), LastSend: peer.LastSend().Unix(), LastPong: peer.LastPong(), Version: peer.Version(), Ip: ipAddress, Port: int(peer.Port()), Latency: peer.PingTime(), Caps: fmt.Sprintf("%v", caps)} +} + +type JSReceipt struct { + CreatedContract bool `json:"createdContract"` + Address string `json:"address"` + Hash string `json:"hash"` + Sender string `json:"sender"` +} + +func NewJSReciept(contractCreation bool, creationAddress, hash, address []byte) *JSReceipt { + return &JSReceipt{ + contractCreation, + ethutil.Bytes2Hex(creationAddress), + ethutil.Bytes2Hex(hash), + ethutil.Bytes2Hex(address), + } +} + +type JSMessage struct { + To string `json:"to"` + From string `json:"from"` + Input string `json:"input"` + Output string `json:"output"` + Path int32 `json:"path"` + Origin string `json:"origin"` + Timestamp int32 `json:"timestamp"` + Coinbase string `json:"coinbase"` + Block string `json:"block"` + Number int32 `json:"number"` + Value string `json:"value"` +} + +func NewJSMessage(message *ethstate.Message) JSMessage { + return JSMessage{ + To: ethutil.Bytes2Hex(message.To), + From: ethutil.Bytes2Hex(message.From), + Input: ethutil.Bytes2Hex(message.Input), + Output: ethutil.Bytes2Hex(message.Output), + Path: int32(message.Path), + Origin: ethutil.Bytes2Hex(message.Origin), + Timestamp: int32(message.Timestamp), + Coinbase: ethutil.Bytes2Hex(message.Origin), + Block: ethutil.Bytes2Hex(message.Block), + Number: int32(message.Number.Int64()), + Value: message.Value.String(), + } +} diff --git a/ethpipe/object.go b/ethpipe/object.go new file mode 100644 index 000000000..356ed788c --- /dev/null +++ b/ethpipe/object.go @@ -0,0 +1,26 @@ +package ethpipe + +import ( + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" +) + +type Object struct { + *ethstate.StateObject +} + +func (self *Object) StorageString(str string) *ethutil.Value { + if ethutil.IsHex(str) { + return self.Storage(ethutil.Hex2Bytes(str[2:])) + } else { + return self.Storage(ethutil.RightPadBytes([]byte(str), 32)) + } +} + +func (self *Object) StorageValue(addr *ethutil.Value) *ethutil.Value { + return self.Storage(addr.Bytes()) +} + +func (self *Object) Storage(addr []byte) *ethutil.Value { + return self.StateObject.GetStorage(ethutil.BigD(addr)) +} diff --git a/ethpipe/pipe.go b/ethpipe/pipe.go new file mode 100644 index 000000000..13085c887 --- /dev/null +++ b/ethpipe/pipe.go @@ -0,0 +1,171 @@ +package ethpipe + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethlog" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/vm" +) + +var logger = ethlog.NewLogger("PIPE") + +type VmVars struct { + State *ethstate.State +} + +type Pipe struct { + obj ethchain.EthManager + stateManager *ethchain.StateManager + blockChain *ethchain.ChainManager + world *World + + Vm VmVars +} + +func New(obj ethchain.EthManager) *Pipe { + pipe := &Pipe{ + obj: obj, + stateManager: obj.StateManager(), + blockChain: obj.ChainManager(), + } + pipe.world = NewWorld(pipe) + + return pipe +} + +func (self *Pipe) Balance(addr []byte) *ethutil.Value { + return ethutil.NewValue(self.World().safeGet(addr).Balance) +} + +func (self *Pipe) Nonce(addr []byte) uint64 { + return self.World().safeGet(addr).Nonce +} + +func (self *Pipe) Execute(addr []byte, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { + return self.ExecuteObject(&Object{self.World().safeGet(addr)}, data, value, gas, price) +} + +func (self *Pipe) ExecuteObject(object *Object, data []byte, value, gas, price *ethutil.Value) ([]byte, error) { + var ( + initiator = ethstate.NewStateObject(self.obj.KeyManager().KeyPair().Address()) + block = self.blockChain.CurrentBlock + ) + + self.Vm.State = self.World().State().Copy() + + evm := vm.New(NewEnv(self.Vm.State, block, value.BigInt(), initiator.Address()), vm.Type(ethutil.Config.VmType)) + + msg := vm.NewExecution(evm, object.Address(), data, gas.BigInt(), price.BigInt(), value.BigInt()) + ret, err := msg.Exec(object.Address(), initiator) + + fmt.Println("returned from call", ret, err) + + return ret, err +} + +func (self *Pipe) Block(hash []byte) *ethchain.Block { + return self.blockChain.GetBlock(hash) +} + +func (self *Pipe) Storage(addr, storageAddr []byte) *ethutil.Value { + return self.World().safeGet(addr).GetStorage(ethutil.BigD(storageAddr)) +} + +func (self *Pipe) ToAddress(priv []byte) []byte { + pair, err := ethcrypto.NewKeyPairFromSec(priv) + if err != nil { + return nil + } + + return pair.Address() +} + +func (self *Pipe) Exists(addr []byte) bool { + return self.World().Get(addr) != nil +} + +func (self *Pipe) TransactString(key *ethcrypto.KeyPair, rec string, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { + // Check if an address is stored by this address + var hash []byte + addr := self.World().Config().Get("NameReg").StorageString(rec).Bytes() + if len(addr) > 0 { + hash = addr + } else if ethutil.IsHex(rec) { + hash = ethutil.Hex2Bytes(rec[2:]) + } else { + hash = ethutil.Hex2Bytes(rec) + } + + return self.Transact(key, hash, value, gas, price, data) +} + +func (self *Pipe) Transact(key *ethcrypto.KeyPair, rec []byte, value, gas, price *ethutil.Value, data []byte) ([]byte, error) { + var hash []byte + var contractCreation bool + if rec == nil { + contractCreation = true + } + + var tx *ethchain.Transaction + // Compile and assemble the given data + if contractCreation { + script, err := ethutil.Compile(string(data), false) + if err != nil { + return nil, err + } + + tx = ethchain.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), script) + } else { + data := ethutil.StringToByteFunc(string(data), func(s string) (ret []byte) { + slice := strings.Split(s, "\n") + for _, dataItem := range slice { + d := ethutil.FormatData(dataItem) + ret = append(ret, d...) + } + return + }) + + tx = ethchain.NewTransactionMessage(hash, value.BigInt(), gas.BigInt(), price.BigInt(), data) + } + + acc := self.stateManager.TransState().GetOrNewStateObject(key.Address()) + tx.Nonce = acc.Nonce + acc.Nonce += 1 + self.stateManager.TransState().UpdateStateObject(acc) + + tx.Sign(key.PrivateKey) + self.obj.TxPool().QueueTransaction(tx) + + if contractCreation { + addr := tx.CreationAddress(self.World().State()) + logger.Infof("Contract addr %x\n", addr) + + return addr, nil + } + + return tx.Hash(), nil +} + +func (self *Pipe) PushTx(tx *ethchain.Transaction) ([]byte, error) { + self.obj.TxPool().QueueTransaction(tx) + if tx.Recipient == nil { + addr := tx.CreationAddress(self.World().State()) + logger.Infof("Contract addr %x\n", addr) + return addr, nil + } + return tx.Hash(), nil +} + +func (self *Pipe) CompileMutan(code string) ([]byte, error) { + data, err := ethutil.Compile(code, false) + if err != nil { + return nil, err + } + + return data, nil +} diff --git a/ethpipe/pipe_test.go b/ethpipe/pipe_test.go new file mode 100644 index 000000000..3b5dc5e4c --- /dev/null +++ b/ethpipe/pipe_test.go @@ -0,0 +1,58 @@ +package ethpipe + +import ( + "testing" + + "github.com/ethereum/go-ethereum/ethcrypto" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/ethutil" +) + +func Val(v interface{}) *ethutil.Value { + return ethutil.NewValue(v) +} + +func TestNew(t *testing.T) { + pipe := New(nil) + + var addr, privy, recp, data []byte + var object *ethstate.StateObject + var key *ethcrypto.KeyPair + + world := pipe.World() + world.Get(addr) + world.Coinbase() + world.IsMining() + world.IsListening() + world.State() + peers := world.Peers() + peers.Len() + + // Shortcut functions + pipe.Balance(addr) + pipe.Nonce(addr) + pipe.Block(addr) + pipe.Storage(addr, addr) + pipe.ToAddress(privy) + pipe.Exists(addr) + // Doesn't change state + pipe.Execute(addr, nil, Val(0), Val(1000000), Val(10)) + // Doesn't change state + pipe.ExecuteObject(object, nil, Val(0), Val(1000000), Val(10)) + + conf := world.Config() + namereg := conf.Get("NameReg") + namereg.Storage(addr) + + var err error + // Transact + err = pipe.Transact(key, recp, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), nil) + if err != nil { + t.Error(err) + } + // Create + err = pipe.Transact(key, nil, ethutil.NewValue(0), ethutil.NewValue(0), ethutil.NewValue(0), data) + if err != nil { + t.Error(err) + } +} diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go new file mode 100644 index 000000000..140726bfe --- /dev/null +++ b/ethpipe/vm_env.go @@ -0,0 +1,39 @@ +package ethpipe + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/ethchain" + "github.com/ethereum/go-ethereum/ethstate" + "github.com/ethereum/go-ethereum/vm" +) + +type VMEnv struct { + state *ethstate.State + block *ethchain.Block + value *big.Int + sender []byte +} + +func NewEnv(state *ethstate.State, block *ethchain.Block, value *big.Int, sender []byte) *VMEnv { + return &VMEnv{ + state: state, + block: block, + value: value, + sender: sender, + } +} + +func (self *VMEnv) Origin() []byte { return self.sender } +func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } +func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } +func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } +func (self *VMEnv) Time() int64 { return self.block.Time } +func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } +func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } +func (self *VMEnv) Value() *big.Int { return self.value } +func (self *VMEnv) State() *ethstate.State { return self.state } +func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { + return vm.Transfer(from, to, amount) +} diff --git a/ethpipe/world.go b/ethpipe/world.go new file mode 100644 index 000000000..e34bd31aa --- /dev/null +++ b/ethpipe/world.go @@ -0,0 +1,64 @@ +package ethpipe + +import ( + "container/list" + + "github.com/ethereum/go-ethereum/ethstate" +) + +type World struct { + pipe *Pipe + cfg *Config +} + +func NewWorld(pipe *Pipe) *World { + world := &World{pipe, nil} + world.cfg = &Config{pipe} + + return world +} + +func (self *Pipe) World() *World { + return self.world +} + +func (self *World) State() *ethstate.State { + return self.pipe.stateManager.CurrentState() +} + +func (self *World) Get(addr []byte) *Object { + return &Object{self.State().GetStateObject(addr)} +} + +func (self *World) SafeGet(addr []byte) *Object { + return &Object{self.safeGet(addr)} +} + +func (self *World) safeGet(addr []byte) *ethstate.StateObject { + object := self.State().GetStateObject(addr) + if object == nil { + object = ethstate.NewStateObject(addr) + } + + return object +} + +func (self *World) Coinbase() *ethstate.StateObject { + return nil +} + +func (self *World) IsMining() bool { + return self.pipe.obj.IsMining() +} + +func (self *World) IsListening() bool { + return self.pipe.obj.IsListening() +} + +func (self *World) Peers() *list.List { + return self.pipe.obj.Peers() +} + +func (self *World) Config() *Config { + return self.cfg +} |