diff --git a/Gopkg.lock b/Gopkg.lock index 5defd78d1..220a337ec 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -20,22 +20,10 @@ version = "v1.1.0" [[projects]] - name = "github.com/go-kit/kit" - packages = ["log"] - revision = "4dc7be5d2d12881735283bcab7352178e190fc71" - version = "v0.6.0" - -[[projects]] - name = "github.com/go-logfmt/logfmt" + name = "github.com/go-yaml/yaml" packages = ["."] - revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" - version = "v0.3.0" - -[[projects]] - name = "github.com/go-stack/stack" - packages = ["."] - revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" - version = "v1.7.0" + revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5" + version = "v2.1.1" [[projects]] branch = "master" @@ -44,10 +32,10 @@ revision = "553a641470496b2327abcac10b36396bd98e45c9" [[projects]] - branch = "master" - name = "github.com/kr/logfmt" + name = "github.com/pkg/errors" packages = ["."] - revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" [[projects]] name = "github.com/pmezard/go-difflib" @@ -138,6 +126,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "333dfa54a358d83b266025eff7f15854652631d90e18e61fa75723c5a030778b" + inputs-digest = "7e6d4161196284974f07ba9655d21ee9b4fe1478ef0e054e159df73aeec1343a" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 053aa3655..0c6af0f5e 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -55,3 +55,11 @@ [[constraint]] name = "github.com/sirupsen/logrus" version = "1.0.5" + +[[constraint]] + name = "github.com/pkg/errors" + version = "0.8.0" + +[[constraint]] + name = "github.com/go-yaml/yaml" + version = "2.1.1" diff --git a/Makefile b/Makefile index d62e2bc11..31e7a7429 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,10 @@ BRANCH = "master" +BUILD_TIME = "$(shell date -u +\"%Y-%m-%dT%H:%M:%SZ\")" VERSION = $(shell cat ./VERSION) -SEEDS ?= "127.0.0.1:20333" -PORT ?= "3000" -DBFILE ?= "chain" +NETMODE ?= "privnet" build: - @go build -o ./bin/neo-go ./cli/main.go + @go build -ldflags "-X github.com/CityOfZion/neo-go/pkg/network.Version=${VERSION}-dev -X github.com/CityOfZion/neo-go/pkg/network.BuildTime=${BUILD_TIME}" -o ./bin/neo-go ./cli/main.go check-version: git fetch && (! git rev-list ${VERSION}) @@ -17,10 +16,10 @@ push-tag: git checkout ${BRANCH} git pull origin ${BRANCH} git tag ${VERSION} - git push origin ${BRANCH} --tags + git push origin ${VERSION} run: build - ./bin/neo-go node -seed ${SEEDS} -tcp ${PORT} -dbfile ${DBFILE} --relay true + ./bin/neo-go node -config-path ./config -${NETMODE} test: @go test ./... -cover diff --git a/VERSION b/VERSION index ae6dd4e20..c25c8e5b7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.29.0 +0.30.0 diff --git a/circle.yml b/circle.yml index 5801df04c..ecc2dc343 100644 --- a/circle.yml +++ b/circle.yml @@ -4,17 +4,18 @@ jobs: working_directory: /go/src/github.com/CityOfZion/neo-go docker: - image: vidsyhq/go-builder:latest + environment: + BUILD: false steps: - checkout - - run: go get -u github.com/golang/dep/cmd/dep - - run: dep ensure - restore_cache: - key: dependency-cache-{{ .Revision }} - - run: BUILD=false /scripts/build.sh + key: dependency-cache-{{ checksum "Gopkg.toml" }}-{{ checksum "VERSION" }} + - run: /scripts/build.sh - save_cache: - key: dependency-cache-{{ .Revision }} + key: dependency-cache-{{ checksum "Gopkg.toml" }}-{{ checksum "VERSION" }} paths: - vendor + - /go/pkg test: working_directory: /go/src/github.com/CityOfZion/neo-go docker: @@ -22,7 +23,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ .Revision }} + key: dependency-cache-{{ checksum "Gopkg.toml" }}-{{ checksum "VERSION" }} - run: make test vet: working_directory: /go/src/github.com/CityOfZion/neo-go @@ -31,7 +32,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ .Revision }} + key: dependency-cache-{{ checksum "Gopkg.toml" }}-{{ checksum "VERSION" }} - run: make vet check_version: working_directory: /go/src/github.com/CityOfZion/neo-go @@ -46,8 +47,8 @@ jobs: - image: vidsyhq/go-builder:latest steps: - checkout - - run: go get -u github.com/golang/dep/cmd/dep - - run: dep ensure + - restore_cache: + key: dependency-cache-{{ checksum "Gopkg.toml" }}-{{ checksum "VERSION" }} - run: make build workflows: @@ -79,4 +80,4 @@ workflows: - install_deps filters: tags: - only: /[0-9]+\.[0-9]+\.[0-9]+/ \ No newline at end of file + only: /[0-9]+\.[0-9]+\.[0-9]+/ diff --git a/cli/server/server.go b/cli/server/server.go index 25adceb8e..a226e733d 100644 --- a/cli/server/server.go +++ b/cli/server/server.go @@ -2,7 +2,6 @@ package server import ( "fmt" - "strings" "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/network" @@ -17,11 +16,7 @@ func NewCommand() cli.Command { Usage: "start a NEO node", Action: startServer, Flags: []cli.Flag{ - cli.IntFlag{Name: "tcp"}, - cli.IntFlag{Name: "rpc"}, - cli.BoolFlag{Name: "relay, r"}, - cli.StringFlag{Name: "seed"}, - cli.StringFlag{Name: "dbfile"}, + cli.StringFlag{Name: "config-path"}, cli.BoolFlag{Name: "privnet, p"}, cli.BoolFlag{Name: "mainnet, m"}, cli.BoolFlag{Name: "testnet, t"}, @@ -38,21 +33,21 @@ func startServer(ctx *cli.Context) error { net = network.ModeMainNet } - cfg := network.Config{ - UserAgent: "/NEO-GO:0.26.0/", - ListenTCP: uint16(ctx.Int("tcp")), - Seeds: parseSeeds(ctx.String("seed")), - Net: net, - Relay: ctx.Bool("relay"), + configPath := "./config" + configPath = ctx.String("config-path") + config, err := network.LoadConfig(configPath, net) + if err != nil { + return err } - chain, err := newBlockchain(net, ctx.String("dbfile")) + serverConfig := network.NewServerConfig(config) + chain, err := newBlockchain(net, config.ApplicationConfiguration.DataDirectoryPath) if err != nil { err = fmt.Errorf("could not initialize blockhain: %s", err) return cli.NewExitError(err, 1) } - s := network.NewServer(cfg, chain) + s := network.NewServer(serverConfig, chain) s.Start() return nil } @@ -80,14 +75,3 @@ func newBlockchain(net network.NetMode, path string) (*core.Blockchain, error) { startHash, ), nil } - -func parseSeeds(s string) []string { - if len(s) == 0 { - return nil - } - seeds := strings.Split(s, ",") - if len(seeds) == 0 { - return nil - } - return seeds -} diff --git a/config/protocol.mainnet.yml b/config/protocol.mainnet.yml new file mode 100644 index 000000000..a9496485e --- /dev/null +++ b/config/protocol.mainnet.yml @@ -0,0 +1,32 @@ +ProtocolConfiguration: + Magic: 7630401 + AddressVersion: 23 + StandbyValidators: + - 03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c + - 02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093 + - 03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a + - 02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554 + - 024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d + - 02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e + - 02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70 + SeedList: + - seed1.neo.org:10333 + - seed2.neo.org:10333 + - seed3.neo.org:10333 + - seed4.neo.org:10333 + - seed5.neo.org:10333 + SystemFee: + EnrollmentTransaction: 1000 + IssueTransaction: 500 + PublishTransaction: 500 + RegisterTransaction: 10000 + +ApplicationConfiguration: + DataDirectoryPath: "./chains/mainnet" + RPCPort: 20332 + NodePort: 20333 + Relay: true + DialTimeout: 3 + ProtoTickInterval: 10 + MaxPeers: 50 + diff --git a/config/protocol.privnet.yml b/config/protocol.privnet.yml new file mode 100644 index 000000000..7183b787e --- /dev/null +++ b/config/protocol.privnet.yml @@ -0,0 +1,27 @@ +ProtocolConfiguration: + Magic: 56753 + AddressVersion: 23 + StandbyValidators: + - 02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2 + - 02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e + - 03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699 + - 02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62 + SeedList: + - 127.0.0.1:20333 + - 127.0.0.1:20334 + - 127.0.0.1:20335 + - 127.0.0.1:20336 + SystemFee: + EnrollmentTransaction: 1000 + IssueTransaction: 500 + PublishTransaction: 500 + RegisterTransaction: 10000 + +ApplicationConfiguration: + DataDirectoryPath: "./chains/privnet" + RPCPort: 20332 + NodePort: 20333 + Relay: true + DialTimeout: 3 + ProtoTickInterval: 10 + MaxPeers: 50 diff --git a/config/protocol.testnet.yml b/config/protocol.testnet.yml new file mode 100644 index 000000000..492595674 --- /dev/null +++ b/config/protocol.testnet.yml @@ -0,0 +1,31 @@ +ProtocolConfiguration: + Magic: 1953787457 + AddressVersion: 23 + StandbyValidators: + - 0327da12b5c40200e9f65569476bbff2218da4f32548ff43b6387ec1416a231ee8 + - 026ce35b29147ad09e4afe4ec4a7319095f08198fa8babbe3c56e970b143528d22 + - 0209e7fd41dfb5c2f8dc72eb30358ac100ea8c72da18847befe06eade68cebfcb9 + - 039dafd8571a641058ccc832c5e2111ea39b09c0bde36050914384f7a48bce9bf9 + - 038dddc06ce687677a53d54f096d2591ba2302068cf123c1f2d75c2dddc5425579 + - 02d02b1873a0863cd042cc717da31cea0d7cf9db32b74d4c72c01b0011503e2e22 + - 034ff5ceeac41acf22cd5ed2da17a6df4dd8358fcb2bfb1a43208ad0feaab2746b + SeedList: + - 18.218.97.227:20333 + - 18.219.30.120:20333 + - 18.219.13.91:20333 + - 13.59.116.121:20333 + - 18.218.255.178:20333 + SystemFee: + EnrollmentTransaction: 10 + IssueTransaction: 5 + PublishTransaction: 5 + RegisterTransaction: 100 + +ApplicationConfiguration: + DataDirectoryPath: "./chains/testnet" + RPCPort: 20332 + NodePort: 20333 + Relay: true + DialTimeout: 3 + ProtoTickInterval: 10 + MaxPeers: 50 diff --git a/pkg/network/config.go b/pkg/network/config.go new file mode 100644 index 000000000..f7f8b1769 --- /dev/null +++ b/pkg/network/config.go @@ -0,0 +1,95 @@ +package network + +import ( + "fmt" + "io/ioutil" + "os" + "time" + + "github.com/go-yaml/yaml" + "github.com/pkg/errors" +) + +const ( + userAgentFormat = "/NEO-GO:%s/" +) + +var ( + // Version the version of the node, set at build time. + Version string + + // BuildTime the time and date the current version of the node built, + // set at build time. + BuildTime string +) + +type ( + // Config top level struct representing the config + // for the node. + Config struct { + ProtocolConfiguration ProtocolConfiguration `yaml:"ProtocolConfiguration"` + ApplicationConfiguration ApplicationConfiguration `yaml:"ApplicationConfiguration"` + } + + // ProtocolConfiguration represents the protolcol config. + ProtocolConfiguration struct { + Magic NetMode `yaml:"Magic"` + AddressVersion int64 `yaml:"AddressVersion"` + MaxTransactionsPerBlock int64 `yaml:"MaxTransactionsPerBlock"` + StandbyValidators []string `yaml:"StandbyValidators"` + SeedList []string `yaml:"SeedList"` + SystemFee SystemFee `yaml:"SystemFee"` + } + + // SystemFee fees related to system. + SystemFee struct { + EnrollmentTransaction int64 `yaml:"EnrollmentTransaction"` + IssueTransaction int64 `yaml:"IssueTransaction"` + PublishTransaction int64 `yaml:"PublishTransaction"` + RegisterTransaction int64 `yaml:"RegisterTransaction"` + } + + // ApplicationConfiguration config specific to the node. + ApplicationConfiguration struct { + DataDirectoryPath string `yaml:"DataDirectoryPath"` + RPCPort uint16 `yaml:"RPCPort"` + NodePort uint16 `yaml:"NodePort"` + Relay bool `yaml:"Relay"` + DialTimeout time.Duration `yaml:"DialTimeout"` + ProtoTickInterval time.Duration `yaml:"ProtoTickInterval"` + MaxPeers int `yaml:"MaxPeers"` + } +) + +// GenerateUserAgent creates user agent string based on build time environment. +func (c Config) GenerateUserAgent() string { + return fmt.Sprintf(userAgentFormat, Version) +} + +// LoadConfig attempts to load the config from the give +// path and netMode. +func LoadConfig(path string, netMode NetMode) (Config, error) { + configPath := fmt.Sprintf("%s/protocol.%s.yml", path, netMode) + if _, err := os.Stat(configPath); os.IsNotExist(err) { + return Config{}, errors.Wrap(err, "Unable to load config") + } + + configData, err := ioutil.ReadFile(configPath) + if err != nil { + return Config{}, errors.Wrap(err, "Unable to read config") + } + + config := Config{ + ProtocolConfiguration: ProtocolConfiguration{ + SystemFee: SystemFee{}, + }, + ApplicationConfiguration: ApplicationConfiguration{}, + } + + err = yaml.Unmarshal([]byte(configData), &config) + if err != nil { + return Config{}, errors.Wrap(err, "Problem unmarshaling config json data") + } + + return config, nil +} diff --git a/pkg/network/helper_test.go b/pkg/network/helper_test.go index 69f1a5295..72014d3b7 100644 --- a/pkg/network/helper_test.go +++ b/pkg/network/helper_test.go @@ -92,15 +92,15 @@ func (p *localPeer) Version() *payload.Version { func newTestServer() *Server { return &Server{ - Config: Config{}, - chain: testChain{}, - transport: localTransport{}, - discovery: testDiscovery{}, - id: util.RandUint32(1000000, 9999999), - quit: make(chan struct{}), - register: make(chan Peer), - unregister: make(chan peerDrop), - peers: make(map[Peer]bool), + ServerConfig: ServerConfig{}, + chain: testChain{}, + transport: localTransport{}, + discovery: testDiscovery{}, + id: util.RandUint32(1000000, 9999999), + quit: make(chan struct{}), + register: make(chan Peer), + unregister: make(chan peerDrop), + peers: make(map[Peer]bool), } } diff --git a/pkg/network/server.go b/pkg/network/server.go index 48cc427b1..004276a57 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -13,16 +13,12 @@ import ( ) const ( - maxPeers = 50 minPeers = 5 maxBlockBatch = 200 minPoolCount = 30 ) var ( - protoTickInterval = 10 * time.Second - dialTimeout = 3 * time.Second - errPortMismatch = errors.New("port mismatch") errIdenticalID = errors.New("identical node id") errInvalidHandshake = errors.New("invalid handshake") @@ -31,47 +27,12 @@ var ( errInvalidInvType = errors.New("invalid inventory type") ) -// Config holds the server configuration. -type Config struct { - // MaxPeers it the maximum numbers of peers that can - // be connected to the server. - MaxPeers int - - // The user agent of the server. - UserAgent string - - // The listen address of the TCP server. - ListenTCP uint16 - - // The network mode the server will operate on. - // ModePrivNet docker private network. - // ModeTestNet NEO test network. - // ModeMainNet NEO main network. - Net NetMode - - // Relay determins whether the server is forwarding its inventory. - Relay bool - - // Seeds are a list of initial nodes used to establish connectivity. - Seeds []string - - // Maximum duration a single dial may take. - DialTimeout time.Duration - - // The duration between protocol ticks with each connected peer. - // When this is 0, the default interval of 5 seconds will be used. - ProtoTickInterval time.Duration - - // Level of the internal logger. - LogLevel log.Level -} - type ( // Server represents the local Node in the network. Its transport could // be of any kind. Server struct { - // Config holds the Server configuration. - Config + // ServerConfig holds the Server configuration. + ServerConfig // id also known as the nonce of te server. id uint32 @@ -102,29 +63,18 @@ type ( ) // NewServer returns a new Server, initialized with the given configuration. -func NewServer(cfg Config, chain *core.Blockchain) *Server { - if cfg.ProtoTickInterval == 0 { - cfg.ProtoTickInterval = protoTickInterval - } - if cfg.DialTimeout == 0 { - cfg.DialTimeout = dialTimeout - } - if cfg.MaxPeers == 0 { - cfg.MaxPeers = maxPeers - } - log.SetLevel(log.DebugLevel) - +func NewServer(config ServerConfig, chain *core.Blockchain) *Server { s := &Server{ - Config: cfg, - chain: chain, - id: util.RandUint32(1000000, 9999999), - quit: make(chan struct{}), - register: make(chan Peer), - unregister: make(chan peerDrop), - peers: make(map[Peer]bool), + ServerConfig: config, + chain: chain, + id: util.RandUint32(1000000, 9999999), + quit: make(chan struct{}), + register: make(chan Peer), + unregister: make(chan peerDrop), + peers: make(map[Peer]bool), } - s.transport = NewTCPTransport(s, fmt.Sprintf(":%d", cfg.ListenTCP)) + s.transport = NewTCPTransport(s, fmt.Sprintf(":%d", config.ListenTCP)) s.proto = s.transport.Consumer() s.discovery = NewDefaultDiscovery( s.DialTimeout, @@ -163,7 +113,7 @@ func (s *Server) run() { } case <-s.quit: s.transport.Close() - for p, _ := range s.peers { + for p := range s.peers { p.Disconnect(errServerShutdown) } return diff --git a/pkg/network/server_config.go b/pkg/network/server_config.go new file mode 100644 index 000000000..46052590b --- /dev/null +++ b/pkg/network/server_config.go @@ -0,0 +1,62 @@ +package network + +import ( + "time" + + log "github.com/sirupsen/logrus" +) + +type ( + // ServerConfig holds the server configuration. + ServerConfig struct { + // MaxPeers it the maximum numbers of peers that can + // be connected to the server. + MaxPeers int + + // The user agent of the server. + UserAgent string + + // The listen address of the TCP server. + ListenTCP uint16 + + // The network mode the server will operate on. + // ModePrivNet docker private network. + // ModeTestNet NEO test network. + // ModeMainNet NEO main network. + Net NetMode + + // Relay determins whether the server is forwarding its inventory. + Relay bool + + // Seeds are a list of initial nodes used to establish connectivity. + Seeds []string + + // Maximum duration a single dial may take. + DialTimeout time.Duration + + // The duration between protocol ticks with each connected peer. + // When this is 0, the default interval of 5 seconds will be used. + ProtoTickInterval time.Duration + + // Level of the internal logger. + LogLevel log.Level + } +) + +// NewServerConfig creates a new ServerConfig struct +// using the main applications config. +func NewServerConfig(config Config) ServerConfig { + appConfig := config.ApplicationConfiguration + protoConfig := config.ProtocolConfiguration + + return ServerConfig{ + UserAgent: config.GenerateUserAgent(), + ListenTCP: appConfig.NodePort, + Net: protoConfig.Magic, + Relay: appConfig.Relay, + Seeds: protoConfig.SeedList, + DialTimeout: (appConfig.DialTimeout * time.Second), + ProtoTickInterval: (appConfig.ProtoTickInterval * time.Second), + MaxPeers: appConfig.MaxPeers, + } +}