diff options
-rw-r--r-- | cmd/geth/js.go | 1 | ||||
-rw-r--r-- | cmd/utils/flags.go | 6 | ||||
-rw-r--r-- | core/state_transition.go | 2 | ||||
-rw-r--r-- | crypto/key_store_passphrase.go | 114 | ||||
-rw-r--r-- | crypto/key_store_passphrase_test.go | 51 | ||||
-rw-r--r-- | crypto/key_store_plain.go | 18 | ||||
-rw-r--r-- | eth/api.go | 65 | ||||
-rw-r--r-- | eth/downloader/downloader.go | 4 | ||||
-rw-r--r-- | params/protocol_params.go | 2 | ||||
-rw-r--r-- | params/util.go | 6 | ||||
-rw-r--r-- | rpc/inproc.go | 88 |
11 files changed, 190 insertions, 167 deletions
diff --git a/cmd/geth/js.go b/cmd/geth/js.go index e7e28b24b..a4b14d7b1 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -119,7 +119,6 @@ func newLightweightJSRE(docRoot string, client rpc.Client, datadir string, inter lr.SetCtrlCAborts(true) lr.SetWordCompleter(makeCompleter(js)) lr.SetTabCompletionStyle(liner.TabPrints) - lr.SetMultiLineMode(true) js.prompter = lr js.atexit = func() { js.withHistory(datadir, func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8e89b9fb1..adcc0adca 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -181,7 +181,7 @@ var ( GasPriceFlag = cli.StringFlag{ Name: "gasprice", Usage: "Minimal gas price to accept for mining a transactions", - Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(), + Value: new(big.Int).Mul(big.NewInt(20), common.Shannon).String(), } ExtraDataFlag = cli.StringFlag{ Name: "extradata", @@ -350,7 +350,7 @@ var ( GpoMinGasPriceFlag = cli.StringFlag{ Name: "gpomin", Usage: "Minimum suggested gas price", - Value: new(big.Int).Mul(big.NewInt(50), common.Shannon).String(), + Value: new(big.Int).Mul(big.NewInt(20), common.Shannon).String(), } GpoMaxGasPriceFlag = cli.StringFlag{ Name: "gpomax", @@ -672,6 +672,8 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. ethConf.Genesis = core.TestNetGenesisBlock() } state.StartingNonce = 1048576 // (2**20) + // overwrite homestead block + params.HomesteadBlock = params.TestNetHomesteadBlock case ctx.GlobalBool(DevModeFlag.Name): // Override the base network stack configs diff --git a/core/state_transition.go b/core/state_transition.go index 52a46c63d..2887f6228 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -78,7 +78,7 @@ func MessageCreatesContract(msg Message) bool { return msg.To() == nil } -// IntrinsicGas computes the 'intrisic gas' for a message +// IntrinsicGas computes the 'intrinsic gas' for a message // with the given data. func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { igas := new(big.Int) diff --git a/crypto/key_store_passphrase.go b/crypto/key_store_passphrase.go index b7ae9e1de..19e77de91 100644 --- a/crypto/key_store_passphrase.go +++ b/crypto/key_store_passphrase.go @@ -34,7 +34,6 @@ import ( "errors" "fmt" "io" - "reflect" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/randentropy" @@ -62,12 +61,10 @@ type keyStorePassphrase struct { keysDirPath string scryptN int scryptP int - scryptR int - scryptDKLen int } func NewKeyStorePassphrase(path string, scryptN int, scryptP int) KeyStore { - return &keyStorePassphrase{path, scryptN, scryptP, scryptR, scryptDKLen} + return &keyStorePassphrase{path, scryptN, scryptP} } func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) { @@ -75,15 +72,7 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K } func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) { - keyBytes, keyId, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth) - if err == nil { - key = &Key{ - Id: uuid.UUID(keyId), - Address: keyAddr, - PrivateKey: ToECDSA(keyBytes), - } - } - return + return decryptKeyFromFile(ks.keysDirPath, keyAddr, auth) } func (ks keyStorePassphrase) Cleanup(keyAddr common.Address) (err error) { @@ -94,12 +83,22 @@ func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err return getKeyAddresses(ks.keysDirPath) } -func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { +func (ks keyStorePassphrase) StoreKey(key *Key, auth string) error { + keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) + if err != nil { + return err + } + return writeKeyFile(key.Address, ks.keysDirPath, keyjson) +} + +// EncryptKey encrypts a key using the specified scrypt parameters into a json +// blob that can be decrypted later on. +func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { authArray := []byte(auth) salt := randentropy.GetEntropyCSPRNG(32) - derivedKey, err := scrypt.Key(authArray, salt, ks.scryptN, ks.scryptR, ks.scryptP, ks.scryptDKLen) + derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) if err != nil { - return err + return nil, err } encryptKey := derivedKey[:16] keyBytes := FromECDSA(key.PrivateKey) @@ -107,16 +106,15 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) if err != nil { - return err + return nil, err } - mac := Keccak256(derivedKey[16:32], cipherText) scryptParamsJSON := make(map[string]interface{}, 5) - scryptParamsJSON["n"] = ks.scryptN - scryptParamsJSON["r"] = ks.scryptR - scryptParamsJSON["p"] = ks.scryptP - scryptParamsJSON["dklen"] = ks.scryptDKLen + scryptParamsJSON["n"] = scryptN + scryptParamsJSON["r"] = scryptR + scryptParamsJSON["p"] = scryptP + scryptParamsJSON["dklen"] = scryptDKLen scryptParamsJSON["salt"] = hex.EncodeToString(salt) cipherParamsJSON := cipherparamsJSON{ @@ -137,47 +135,69 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { key.Id.String(), version, } - keyJSON, err := json.Marshal(encryptedKeyJSONV3) - if err != nil { - return err - } - - return writeKeyFile(key.Address, ks.keysDirPath, keyJSON) + return json.Marshal(encryptedKeyJSONV3) } -func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) { +func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) error { // only delete if correct passphrase is given - _, _, err = decryptKeyFromFile(ks.keysDirPath, keyAddr, auth) - if err != nil { + if _, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth); err != nil { return err } - return deleteKey(ks.keysDirPath, keyAddr) } -func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) { +// DecryptKey decrypts a key from a json blob, returning the private key itself. +func DecryptKey(keyjson []byte, auth string) (*Key, error) { + // Parse the json into a simple map to fetch the key version m := make(map[string]interface{}) - err = getKey(keysDirPath, keyAddr, &m) - if err != nil { - return + if err := json.Unmarshal(keyjson, &m); err != nil { + return nil, err } - - v := reflect.ValueOf(m["version"]) - if v.Kind() == reflect.String && v.String() == "1" { + // Depending on the version try to parse one way or another + var ( + keyBytes, keyId []byte + err error + ) + if version, ok := m["version"].(string); ok && version == "1" { k := new(encryptedKeyJSONV1) - err = getKey(keysDirPath, keyAddr, &k) - if err != nil { - return + if err := json.Unmarshal(keyjson, k); err != nil { + return nil, err } - return decryptKeyV1(k, auth) + keyBytes, keyId, err = decryptKeyV1(k, auth) } else { k := new(encryptedKeyJSONV3) - err = getKey(keysDirPath, keyAddr, &k) - if err != nil { - return + if err := json.Unmarshal(keyjson, k); err != nil { + return nil, err } - return decryptKeyV3(k, auth) + keyBytes, keyId, err = decryptKeyV3(k, auth) + } + // Handle any decryption errors and return the key + if err != nil { + return nil, err + } + key := ToECDSA(keyBytes) + return &Key{ + Id: uuid.UUID(keyId), + Address: PubkeyToAddress(key.PublicKey), + PrivateKey: key, + }, nil +} + +func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (*Key, error) { + // Load the key from the keystore and decrypt its contents + keyjson, err := getKeyFile(keysDirPath, keyAddr) + if err != nil { + return nil, err + } + key, err := DecryptKey(keyjson, auth) + if err != nil { + return nil, err + } + // Make sure we're really operating on the requested key (no swap attacks) + if keyAddr != key.Address { + return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, keyAddr) } + return key, nil } func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { diff --git a/crypto/key_store_passphrase_test.go b/crypto/key_store_passphrase_test.go new file mode 100644 index 000000000..bcdd58ad9 --- /dev/null +++ b/crypto/key_store_passphrase_test.go @@ -0,0 +1,51 @@ +// 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 crypto + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +// Tests that a json key file can be decrypted and encrypted in multiple rounds. +func TestKeyEncryptDecrypt(t *testing.T) { + address := common.HexToAddress("f626acac23772cbe04dd578bee681b06bdefb9fa") + keyjson := []byte("{\"address\":\"f626acac23772cbe04dd578bee681b06bdefb9fa\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"1bcf0ab9b14459795ce59f63e63255ffd84dc38d31614a5a78e37144d7e4a17f\",\"cipherparams\":{\"iv\":\"df4c7e225ee2d81adef522013e3fbe24\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":262144,\"p\":1,\"r\":8,\"salt\":\"2909a99dd2bfa7079a4b40991773b1083f8512c0c55b9b63402ab0e3dc8db8b3\"},\"mac\":\"4ecf6a4ad92ae2c016cb7c44abade74799480c3303eb024661270dfefdbc7510\"},\"id\":\"b4718210-9a30-4883-b8a6-dbdd08bd0ceb\",\"version\":3}") + password := "" + + // Do a few rounds of decryption and encryption + for i := 0; i < 3; i++ { + // Try a bad password first + if _, err := DecryptKey(keyjson, password+"bad"); err == nil { + t.Error("test %d: json key decrypted with bad password", i) + } + // Decrypt with the correct password + key, err := DecryptKey(keyjson, password) + if err != nil { + t.Errorf("test %d: json key failed to decrypt: %v", i, err) + } + if key.Address != address { + t.Errorf("test %d: key address mismatch: have %x, want %x", i, key.Address, address) + } + // Recrypt with a new password and start over + password += "new data appended" + if keyjson, err = EncryptKey(key, password, LightScryptN, LightScryptP); err != nil { + t.Errorf("test %d: failed to recrypt key %v", err) + } + } +} diff --git a/crypto/key_store_plain.go b/crypto/key_store_plain.go index c1c23f8b8..4ce789a30 100644 --- a/crypto/key_store_plain.go +++ b/crypto/key_store_plain.go @@ -62,18 +62,16 @@ func GenerateNewKeyDefault(ks KeyStore, rand io.Reader, auth string) (key *Key, return key, err } -func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (key *Key, err error) { - key = new(Key) - err = getKey(ks.keysDirPath, keyAddr, key) - return -} - -func getKey(keysDirPath string, keyAddr common.Address, content interface{}) (err error) { - fileContent, err := getKeyFile(keysDirPath, keyAddr) +func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (*Key, error) { + keyjson, err := getKeyFile(ks.keysDirPath, keyAddr) if err != nil { - return + return nil, err + } + key := new(Key) + if err := json.Unmarshal(keyjson, key); err != nil { + return nil, err } - return json.Unmarshal(fileContent, content) + return key, nil } func (ks keyStorePlain) GetKeyAddresses() (addresses []common.Address, err error) { diff --git a/eth/api.go b/eth/api.go index cfbafd79f..38b67a07a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -620,12 +620,12 @@ func (m callmsg) Value() *big.Int { return m.value } func (m callmsg) Data() []byte { return m.data } type CallArgs struct { - From common.Address `json:"from"` - To common.Address `json:"to"` - Gas rpc.HexNumber `json:"gas"` - GasPrice rpc.HexNumber `json:"gasPrice"` - Value rpc.HexNumber `json:"value"` - Data string `json:"data"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Gas rpc.HexNumber `json:"gas"` + GasPrice rpc.HexNumber `json:"gasPrice"` + Value rpc.HexNumber `json:"value"` + Data string `json:"data"` } func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { @@ -653,7 +653,7 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st // Assemble the CALL invocation msg := callmsg{ from: from, - to: &args.To, + to: args.To, gas: args.Gas.BigInt(), gasPrice: args.GasPrice.BigInt(), value: args.Value.BigInt(), @@ -665,6 +665,7 @@ func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (st if msg.gasPrice.Cmp(common.Big0) == 0 { msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) } + // Execute the call and return vmenv := core.NewEnv(stateDb, s.bc, msg, block.Header()) gp := new(core.GasPool).AddGas(common.MaxBig) @@ -1012,13 +1013,13 @@ func (s *PublicTransactionPoolAPI) sign(address common.Address, tx *types.Transa } type SendTxArgs struct { - From common.Address `json:"from"` - To common.Address `json:"to"` - Gas *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - Nonce *rpc.HexNumber `json:"nonce"` + From common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Value *rpc.HexNumber `json:"value"` + Data string `json:"data"` + Nonce *rpc.HexNumber `json:"nonce"` } // SendTransaction will create a transaction for the given transaction argument, sign it and submit it to the @@ -1042,12 +1043,12 @@ func (s *PublicTransactionPoolAPI) SendTransaction(args SendTxArgs) (common.Hash } var tx *types.Transaction - contractCreation := (args.To == common.Address{}) + contractCreation := (args.To == nil) if contractCreation { tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } else { - tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } signedTx, err := s.sign(args.From, tx) @@ -1106,7 +1107,7 @@ func (s *PublicTransactionPoolAPI) Sign(address common.Address, data string) (st type SignTransactionArgs struct { From common.Address - To common.Address + To *common.Address Nonce *rpc.HexNumber Value *rpc.HexNumber Gas *rpc.HexNumber @@ -1132,23 +1133,21 @@ type Tx struct { func (tx *Tx) UnmarshalJSON(b []byte) (err error) { req := struct { - To common.Address `json:"to"` - From common.Address `json:"from"` - Nonce *rpc.HexNumber `json:"nonce"` - Value *rpc.HexNumber `json:"value"` - Data string `json:"data"` - GasLimit *rpc.HexNumber `json:"gas"` - GasPrice *rpc.HexNumber `json:"gasPrice"` - Hash common.Hash `json:"hash"` + To *common.Address `json:"to"` + From common.Address `json:"from"` + Nonce *rpc.HexNumber `json:"nonce"` + Value *rpc.HexNumber `json:"value"` + Data string `json:"data"` + GasLimit *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Hash common.Hash `json:"hash"` }{} if err := json.Unmarshal(b, &req); err != nil { return err } - contractCreation := (req.To == (common.Address{})) - - tx.To = &req.To + tx.To = req.To tx.From = req.From tx.Nonce = req.Nonce tx.Value = req.Value @@ -1172,12 +1171,10 @@ func (tx *Tx) UnmarshalJSON(b []byte) (err error) { tx.GasPrice = rpc.NewHexNumber(int64(50000000000)) } + contractCreation := (req.To == nil) if contractCreation { tx.tx = types.NewContractCreation(tx.Nonce.Uint64(), tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) } else { - if tx.To == nil { - return fmt.Errorf("need to address") - } tx.tx = types.NewTransaction(tx.Nonce.Uint64(), *tx.To, tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) } @@ -1226,12 +1223,12 @@ func (s *PublicTransactionPoolAPI) SignTransaction(args *SignTransactionArgs) (* } var tx *types.Transaction - contractCreation := (args.To == common.Address{}) + contractCreation := (args.To == nil) if contractCreation { tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } else { - tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) } signedTx, err := s.sign(args.From, tx) @@ -1324,7 +1321,7 @@ func (s *PublicTransactionPoolAPI) Resend(tx *Tx, gasPrice, gasLimit *rpc.HexNum } var newTx *types.Transaction - contractCreation := (*tx.tx.To() == common.Address{}) + contractCreation := (tx.tx.To() == nil) if contractCreation { newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data()) } else { diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 017d25704..143d8bde7 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -1263,9 +1263,11 @@ func (d *Downloader) fetchHeaders(p *peer, td *big.Int, from uint64) error { case ch <- false: case <-d.cancelCh: } - return nil } } + if !cont { + return nil + } // Queue not yet full, fetch the next batch from += uint64(len(headers)) getHeaders(from) diff --git a/params/protocol_params.go b/params/protocol_params.go index 71c7035a4..45a9a2549 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -41,7 +41,7 @@ var ( Sha256WordGas = big.NewInt(12) // MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. - GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block. + GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. Sha3Gas = big.NewInt(30) // Once per SHA3 operation. Sha256Gas = big.NewInt(60) // diff --git a/params/util.go b/params/util.go index 856a39e3a..6a49a2013 100644 --- a/params/util.go +++ b/params/util.go @@ -18,7 +18,11 @@ package params import "math/big" -var HomesteadBlock *big.Int = big.NewInt(2000000) +var ( + TestNetHomesteadBlock = big.NewInt(494000) // testnet homestead block + MainNetHomesteadBlock = big.NewInt(1150000) // mainnet homestead block + HomesteadBlock = MainNetHomesteadBlock // homestead block used to check against +) func IsHomestead(blockNumber *big.Int) bool { // for unit tests TODO: flip to true after homestead is live diff --git a/rpc/inproc.go b/rpc/inproc.go index e138ba2c3..3cfbea71c 100644 --- a/rpc/inproc.go +++ b/rpc/inproc.go @@ -16,96 +16,46 @@ package rpc -import "encoding/json" - -// NewInProcRPCClient creates an in-process buffer stream attachment to a given -// RPC server. -func NewInProcRPCClient(handler *Server) Client { - buffer := &inprocBuffer{ - requests: make(chan []byte, 16), - responses: make(chan []byte, 16), - } - client := &inProcClient{ - server: handler, - buffer: buffer, - } - go handler.ServeCodec(NewJSONCodec(client.buffer)) - return client -} +import ( + "encoding/json" + "io" + "net" +) // inProcClient is an in-process buffer stream attached to an RPC server. type inProcClient struct { server *Server - buffer *inprocBuffer + cl io.Closer + enc *json.Encoder + dec *json.Decoder } // Close tears down the request channel of the in-proc client. func (c *inProcClient) Close() { - c.buffer.Close() + c.cl.Close() +} + +// NewInProcRPCClient creates an in-process buffer stream attachment to a given +// RPC server. +func NewInProcRPCClient(handler *Server) Client { + p1, p2 := net.Pipe() + go handler.ServeCodec(NewJSONCodec(p1)) + return &inProcClient{handler, p2, json.NewEncoder(p2), json.NewDecoder(p2)} } // Send marshals a message into a json format and injects in into the client // request channel. func (c *inProcClient) Send(msg interface{}) error { - d, err := json.Marshal(msg) - if err != nil { - return err - } - c.buffer.requests <- d - return nil + return c.enc.Encode(msg) } // Recv reads a message from the response channel and tries to parse it into the // given msg interface. func (c *inProcClient) Recv(msg interface{}) error { - data := <-c.buffer.responses - return json.Unmarshal(data, &msg) + return c.dec.Decode(msg) } // Returns the collection of modules the RPC server offers. func (c *inProcClient) SupportedModules() (map[string]string, error) { return SupportedModules(c) } - -// inprocBuffer represents the connection between the RPC server and console -type inprocBuffer struct { - readBuf []byte // store remaining request bytes after a partial read - requests chan []byte // list with raw serialized requests - responses chan []byte // list with raw serialized responses -} - -// Read will read the next request in json format. -func (b *inprocBuffer) Read(p []byte) (int, error) { - // last read didn't read entire request, return remaining bytes - if len(b.readBuf) > 0 { - n := copy(p, b.readBuf) - if n < len(b.readBuf) { - b.readBuf = b.readBuf[:n] - } else { - b.readBuf = b.readBuf[:0] - } - return n, nil - } - // read next request - req := <-b.requests - n := copy(p, req) - if n < len(req) { - // inprocBuffer too small, store remaining chunk for next read - b.readBuf = req[n:] - } - return n, nil -} - -// Write sends the given buffer to the backend. -func (b *inprocBuffer) Write(p []byte) (n int, err error) { - b.responses <- p - return len(p), nil -} - -// Close cleans up obtained resources. -func (b *inprocBuffer) Close() error { - close(b.requests) - close(b.responses) - - return nil -} |