aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/geth/js.go1
-rw-r--r--cmd/utils/flags.go6
-rw-r--r--core/state_transition.go2
-rw-r--r--crypto/key_store_passphrase.go114
-rw-r--r--crypto/key_store_passphrase_test.go51
-rw-r--r--crypto/key_store_plain.go18
-rw-r--r--eth/api.go65
-rw-r--r--eth/downloader/downloader.go4
-rw-r--r--params/protocol_params.go2
-rw-r--r--params/util.go6
-rw-r--r--rpc/inproc.go88
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
-}