diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 027c6a085..cec424583 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -42,6 +42,7 @@ type EthManager interface { IsListening() bool Peers() *list.List KeyManager() *ethcrypto.KeyManager + ClientIdentity() ethwire.ClientIdentity } type StateManager struct { diff --git a/ethereum.go b/ethereum.go index b78b0658f..35d98e831 100644 --- a/ethereum.go +++ b/ethereum.go @@ -76,9 +76,11 @@ type Ethereum struct { RpcServer *ethrpc.JsonRpcServer keyManager *ethcrypto.KeyManager + + clientIdentity ethwire.ClientIdentity } -func New(db ethutil.Database, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { +func New(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, caps Caps, usePnp bool) (*Ethereum, error) { var err error var nat NAT @@ -94,14 +96,15 @@ func New(db ethutil.Database, keyManager *ethcrypto.KeyManager, caps Caps, usePn nonce, _ := ethutil.RandomUint64() ethereum := &Ethereum{ - shutdownChan: make(chan bool), - quit: make(chan bool), - db: db, - peers: list.New(), - Nonce: nonce, - serverCaps: caps, - nat: nat, - keyManager: keyManager, + shutdownChan: make(chan bool), + quit: make(chan bool), + db: db, + peers: list.New(), + Nonce: nonce, + serverCaps: caps, + nat: nat, + keyManager: keyManager, + clientIdentity: clientIdentity, } ethereum.reactor = ethutil.NewReactorEngine() @@ -123,6 +126,10 @@ func (s *Ethereum) KeyManager() *ethcrypto.KeyManager { return s.keyManager } +func (s *Ethereum) ClientIdentity() ethwire.ClientIdentity { + return s.clientIdentity +} + func (s *Ethereum) BlockChain() *ethchain.BlockChain { return s.blockChain } diff --git a/ethutil/config.go b/ethutil/config.go index d716005b5..c9b86100b 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -5,29 +5,25 @@ import ( "fmt" "github.com/rakyll/globalconf" "os" - "runtime" ) // Config struct -type config struct { +type ConfigManager struct { Db Database - ExecPath string - Debug bool - Paranoia bool - Ver string - ClientString string - Identifier string + ExecPath string + Debug bool + Paranoia bool conf *globalconf.GlobalConf } -var Config *config +var Config *ConfigManager // Read config // // Initialize Config from Config File -func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) *config { +func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager { if Config == nil { // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags _, err := os.Stat(ConfigFile) @@ -44,34 +40,30 @@ func ReadConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix } else { g.ParseAll() } - Config = &config{ExecPath: Datadir, Debug: true, Ver: "0.5.16", conf: g, Identifier: Identifier, Paranoia: true} - Config.SetClientString("Ethereum(G)") + Config = &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true} } return Config } -// Set client string -// -func (c *config) SetClientString(str string) { - os := runtime.GOOS - cust := c.Identifier - Config.ClientString = fmt.Sprintf("%s/v%s/%s/%s/Go", str, c.Ver, cust, os) -} - -func (c *config) SetIdentifier(id string) { - c.Identifier = id - c.Set("id", id) -} - // provides persistence for flags -func (c *config) Set(key, value string) { - f := &flag.Flag{Name: key, Value: &confValue{value}} +func (c *ConfigManager) Save(key string, value interface{}) { + f := &flag.Flag{Name: key, Value: newConfValue(value)} c.conf.Set("", f) } +func (c *ConfigManager) Delete(key string) { + c.conf.Delete("", key) +} + +// private type implementing flag.Value type confValue struct { value string } +// generic constructor to allow persising non-string values directly +func newConfValue(value interface{}) *confValue { + return &confValue{fmt.Sprintf("%v", value)} +} + func (self confValue) String() string { return self.value } func (self confValue) Set(s string) error { self.value = s; return nil } diff --git a/ethwire/client_identity.go b/ethwire/client_identity.go new file mode 100644 index 000000000..e803406d8 --- /dev/null +++ b/ethwire/client_identity.go @@ -0,0 +1,54 @@ +package ethwire + +import ( + "fmt" + "runtime" +) + +// should be used in Peer handleHandshake, incorporate Caps, ProtocolVersion, Pubkey etc. +type ClientIdentity interface { + String() string +} + +type SimpleClientIdentity struct { + clientString string + clientIdentifier string + version string + customIdentifier string + os string + implementation string +} + +func NewSimpleClientIdentity(clientIdentifier string, version string, customIdentifier string) *SimpleClientIdentity { + clientIdentity := &SimpleClientIdentity{ + clientIdentifier: clientIdentifier, + version: version, + customIdentifier: customIdentifier, + os: runtime.GOOS, + implementation: "Go", + } + clientIdentity.init() + return clientIdentity +} + +func (c *SimpleClientIdentity) init() { + c.clientString = fmt.Sprintf("%s/v%s/%s/%s/%s", + c.clientIdentifier, + c.version, + c.customIdentifier, + c.os, + c.implementation) +} + +func (c *SimpleClientIdentity) String() string { + return c.clientString +} + +func (c *SimpleClientIdentity) SetCustomIdentifier(customIdentifier string) { + c.customIdentifier = customIdentifier + c.init() +} + +func (c *SimpleClientIdentity) GetCustomIdentifier() string { + return c.customIdentifier +} diff --git a/ethwire/client_identity_test.go b/ethwire/client_identity_test.go new file mode 100644 index 000000000..f3c8bfd50 --- /dev/null +++ b/ethwire/client_identity_test.go @@ -0,0 +1,30 @@ +package ethwire + +import ( + "fmt" + "runtime" + "testing" +) + +func TestClientIdentity(t *testing.T) { + clientIdentity := NewSimpleClientIdentity("Ethereum(G)", "0.5.16", "test") + clientString := clientIdentity.String() + expected := fmt.Sprintf("Ethereum(G)/v0.5.16/test/%s/Go", runtime.GOOS) + if clientString != expected { + t.Error("Expected clientIdentity to be %v, got %v", expected, clientString) + } + customIdentifier := clientIdentity.GetCustomIdentifier() + if customIdentifier != "test" { + t.Error("Expected clientIdentity.GetCustomIdentifier() to be 'test', got %v", customIdentifier) + } + clientIdentity.SetCustomIdentifier("test2") + customIdentifier = clientIdentity.GetCustomIdentifier() + if customIdentifier != "test2" { + t.Error("Expected clientIdentity.GetCustomIdentifier() to be 'test2', got %v", customIdentifier) + } + clientString = clientIdentity.String() + expected = fmt.Sprintf("Ethereum(G)/v0.5.16/test2/%s/Go", runtime.GOOS) + if clientString != expected { + t.Error("Expected clientIdentity to be %v, got %v", expected, clientString) + } +} diff --git a/peer.go b/peer.go index 8e14c7460..a93d22d93 100644 --- a/peer.go +++ b/peer.go @@ -162,7 +162,7 @@ func NewPeer(conn net.Conn, ethereum *Ethereum, inbound bool) *Peer { pubkey: pubkey, blocksRequested: 10, caps: ethereum.ServerCaps(), - version: ethutil.Config.ClientString, + version: ethereum.ClientIdentity().String(), } } @@ -175,7 +175,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { connected: 0, disconnect: 0, caps: caps, - version: ethutil.Config.ClientString, + version: ethereum.ClientIdentity().String(), } // Set up the connection in another goroutine so we don't block the main thread