diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b50309006..ff2061e09 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,7 +25,8 @@ before_script: test-my-project: stage: test script: - - bash -x build.sh + - make clean + - make use_all_cores - go test -v -race -failfast -parallel 16 -cpu 16 $(go list ./... | grep -v "/vendor/") -coverprofile cover.out - cd rpc && go test -test.bench ^BenchmarkPersistentCaller_Call$ -test.run ^$ && cd - - bash cleanupDB.sh || true diff --git a/.travis.yml b/.travis.yml index 99b061b1f..23f022dff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,8 @@ script: golint ./... | grep -v 'vendor/' | grep -v 'server/' | grep -v 'utils/' | reviewdog -f=golint -reporter=github-pr-review || true before_deploy: - - bash build.sh + - make clean + - make use_all_cores - mkdir -p build - tar czvf build/CovenantSQL-$TRAVIS_TAG.$TRAVIS_OS_NAME-amd64.tar.gz $(ls bin/cql* | grep -v test) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e4dcdce..562baa25a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## [v0.1.0](https://github.com/CovenantSQL/CovenantSQL/tree/v0.1.0) (2018-12-29) + +[Full Changelog](https://github.com/CovenantSQL/CovenantSQL/compare/v0.0.6...v0.1.0) + +**Closed issues:** + +- Private Key Format should be human readable [\#144](https://github.com/CovenantSQL/CovenantSQL/issues/144) + +**Merged pull requests:** + +- Change test config IsTestMode to true. [\#171](https://github.com/CovenantSQL/CovenantSQL/pull/171) ([laodouya](https://github.com/laodouya)) +- Update node\_c config for testnet [\#170](https://github.com/CovenantSQL/CovenantSQL/pull/170) ([leventeliu](https://github.com/leventeliu)) +- Fix miner crash on billing [\#169](https://github.com/CovenantSQL/CovenantSQL/pull/169) ([leventeliu](https://github.com/leventeliu)) +- Update ci config [\#168](https://github.com/CovenantSQL/CovenantSQL/pull/168) ([xq262144](https://github.com/xq262144)) +- Update observer api to support queries pagination [\#167](https://github.com/CovenantSQL/CovenantSQL/pull/167) ([xq262144](https://github.com/xq262144)) +- Add testnet parameters package and fix cql-utils congen tool [\#166](https://github.com/CovenantSQL/CovenantSQL/pull/166) ([leventeliu](https://github.com/leventeliu)) +- Update ci config, run reviewdog on travis, other in gitlab [\#165](https://github.com/CovenantSQL/CovenantSQL/pull/165) ([xq262144](https://github.com/xq262144)) +- Add README-zh for cql-utils [\#161](https://github.com/CovenantSQL/CovenantSQL/pull/161) ([leventeliu](https://github.com/leventeliu)) +- Update client readme and example [\#160](https://github.com/CovenantSQL/CovenantSQL/pull/160) ([laodouya](https://github.com/laodouya)) +- Add more test cases for ETLS [\#159](https://github.com/CovenantSQL/CovenantSQL/pull/159) ([auxten](https://github.com/auxten)) +- Reduce unnecessary object copy while producing/applying new block [\#158](https://github.com/CovenantSQL/CovenantSQL/pull/158) ([leventeliu](https://github.com/leventeliu)) +- HTTP\(S\) Adapter Improvements and various query sanitizations [\#157](https://github.com/CovenantSQL/CovenantSQL/pull/157) ([xq262144](https://github.com/xq262144)) +- Add raw socket magic header and encrypted magic header for ETLS [\#156](https://github.com/CovenantSQL/CovenantSQL/pull/156) ([auxten](https://github.com/auxten)) +- Fix RunCommandNB pipe issue [\#155](https://github.com/CovenantSQL/CovenantSQL/pull/155) ([auxten](https://github.com/auxten)) +- Fix some issues in block producer [\#154](https://github.com/CovenantSQL/CovenantSQL/pull/154) ([leventeliu](https://github.com/leventeliu)) +- Use docker mapping port for node\_c [\#150](https://github.com/CovenantSQL/CovenantSQL/pull/150) ([auxten](https://github.com/auxten)) +- Update default makefile task to all [\#147](https://github.com/CovenantSQL/CovenantSQL/pull/147) ([draveness](https://github.com/draveness)) +- Save & load private key in base58 format [\#146](https://github.com/CovenantSQL/CovenantSQL/pull/146) ([draveness](https://github.com/draveness)) +- Add billing process and chain bus support [\#145](https://github.com/CovenantSQL/CovenantSQL/pull/145) ([zeqing-guo](https://github.com/zeqing-guo)) +- Refactor build.sh and Makefile [\#142](https://github.com/CovenantSQL/CovenantSQL/pull/142) ([laodouya](https://github.com/laodouya)) +- Block producer refactor and chain bus integration [\#135](https://github.com/CovenantSQL/CovenantSQL/pull/135) ([leventeliu](https://github.com/leventeliu)) + ## [v0.0.6](https://github.com/CovenantSQL/CovenantSQL/tree/v0.0.6) (2018-12-18) [Full Changelog](https://github.com/CovenantSQL/CovenantSQL/compare/v0.0.5...v0.0.6) diff --git a/Makefile b/Makefile index 02cb41327..e85983717 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,24 @@ default: all +# Do a parallel build with multiple jobs, based on the number of CPUs online +# in this system: 'make -j8' on a 8-CPU system, etc. +ifeq ($(JOBS),) + JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) + ifeq ($(JOBS),) + JOBS := $(shell sysctl -n hw.logicalcpu 2>/dev/null) + ifeq ($(JOBS),) + JOBS := 1 + endif + endif +endif + +use_all_cores: + make -j$(JOBS) all + +BUILDER := covenantsql/covenantsql-builder IMAGE := covenantsql/covenantsql +OB_IMAGE := covenantsql/covenantsql-observer + GIT_COMMIT ?= $(shell git rev-parse --short HEAD) GIT_DIRTY ?= $(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) GIT_DESCRIBE ?= $(shell git describe --tags --always) @@ -11,18 +29,47 @@ SHIP_VERSION := $(shell docker image inspect -f "{{ .Config.Labels.version }}" $ IMAGE_TAR := $(subst /,_,$(IMAGE)).$(SHIP_VERSION).tar IMAGE_TAR_GZ := $(IMAGE_TAR).gz - status: @echo "Commit: $(COMMIT) Version: $(VERSION) Ship Version: $(SHIP_VERSION)" -docker: status + +builder: status + docker build \ + --tag $(BUILDER):$(VERSION) \ + --tag $(BUILDER):latest \ + --build-arg BUILD_ARG=use_all_cores \ + -f docker/builder.Dockerfile \ + . + +runner: builder docker build \ --tag $(IMAGE):$(VERSION) \ --tag $(IMAGE):latest \ --build-arg COMMIT=$(COMMIT) \ --build-arg VERSION=$(VERSION) \ + -f docker/Dockerfile \ + . + +observer_docker: builder + docker build \ + --tag $(OB_IMAGE):$(VERSION) \ + --tag $(OB_IMAGE):latest \ + --build-arg COMMIT=$(COMMIT) \ + --build-arg VERSION=$(VERSION) \ + -f docker/observer.Dockerfile \ . +docker: runner observer_docker + +docker_clean: status + docker rmi -f $(BUILDER):latest + docker rmi -f $(IMAGE):latest + docker rmi -f $(OB_IMAGE):latest + docker rmi -f $(BUILDER):$(VERSION) + docker rmi -f $(IMAGE):$(VERSION) + docker rmi -f $(OB_IMAGE):$(VERSION) + + save: status ifeq ($(SHIP_VERSION),) $(error No version to ship, please build first) @@ -41,20 +88,134 @@ stop: logs: docker-compose logs -f --tail=10 +push_testnet: + docker tag $(OB_IMAGE):$(VERSION) $(OB_IMAGE):testnet + docker push $(OB_IMAGE):testnet + docker tag $(IMAGE):$(VERSION) $(IMAGE):testnet + docker push $(IMAGE):testnet + push: + docker push $(OB_IMAGE):$(VERSION) + docker push $(OB_IMAGE):latest docker push $(IMAGE):$(VERSION) docker push $(IMAGE):latest -bp: - ./build.sh bp -miner: - ./build.sh miner -client: - ./build.sh client +branch := $(shell git rev-parse --abbrev-ref HEAD) +builddate := $(shell date +%Y%m%d%H%M%S) + +unamestr := $(shell uname) + +ifeq ($(unamestr),"Linux") +platform := "linux" +endif + +version := $(branch)-$(GIT_COMMIT)-$(builddate) + +tags := $(platform) sqlite_omit_load_extension +testtags := $(platform) sqlite_omit_load_extension testbinary +test_flags := -coverpkg github.com/CovenantSQL/CovenantSQL/... -cover -race -c + +ldflags_role_bp := -X main.version=$(version) -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=B $$GOLDFLAGS +ldflags_role_miner := -X main.version=$(version) -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=M $$GOLDFLAGS +ldflags_role_client := -X main.version=$(version) -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=C $$GOLDFLAGS +ldflags_role_client_simple_log := $(ldflags_role_client) -X github.com/CovenantSQL/CovenantSQL/utils/log.SimpleLog=Y + +GOTEST := CGO_ENABLED=1 go test $(test_flags) -tags "$(testtags)" +GOBUILD := CGO_ENABLED=1 go build -tags "$(tags)" + +bin/cqld.test: + $(GOTEST) \ + -ldflags "$(ldflags_role_bp)" \ + -o bin/cqld.test \ + github.com/CovenantSQL/CovenantSQL/cmd/cqld + +bin/cqld: + $(GOBUILD) \ + -ldflags "$(ldflags_role_bp)" \ + -o bin/cqld \ + github.com/CovenantSQL/CovenantSQL/cmd/cqld + +bin/cql-minerd.test: + $(GOTEST) \ + -ldflags "$(ldflags_role_miner)" \ + -o bin/cql-minerd.test \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-minerd + +bin/cql-minerd: + $(GOBUILD) \ + -ldflags "$(ldflags_role_miner)" \ + -o bin/cql-minerd \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-minerd + +bin/cql-observer.test: + $(GOTEST) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-observer.test \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-observer + +bin/cql-observer: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-observer \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-observer + +bin/cql-utils: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client_simple_log)" \ + -o bin/cql-utils \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-utils + +bin/cql: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client_simple_log)" \ + -o bin/cql \ + github.com/CovenantSQL/CovenantSQL/cmd/cql + +bin/cql-fuse: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client_simple_log)" \ + -o bin/cql-fuse \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-fuse + +bin/cql-adapter: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-adapter \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-adapter + +bin/cql-mysql-adapter: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-mysql-adapter \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-mysql-adapter + +bin/cql-faucet: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-faucet \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-faucet + +bin/cql-explorer: + $(GOBUILD) \ + -ldflags "$(ldflags_role_client)" \ + -o bin/cql-explorer \ + github.com/CovenantSQL/CovenantSQL/cmd/cql-explorer + +bp: bin/cqld.test bin/cqld + +miner: bin/cql-minerd.test bin/cql-minerd + +observer: bin/cql-observer.test bin/cql-observer + +client: bin/cql-utils bin/cql bin/cql-fuse bin/cql-adapter bin/cql-mysql-adapter bin/cql-faucet bin/cql-explorer + +all: bp miner observer client -all: - ./build.sh +clean: + rm -rf bin/cql* -.PHONY: status docker save start stop logs push bp miner client all +.PHONY: status start stop logs push push_testnet clean \ + bin/cqld.test bin/cqld bin/cql-minerd.test bin/cql-minerd bin/cql-utils \ + bin/cql bin/cql-fuse bin/cql-adapter bin/cql-mysql-adapter bin/cql-faucet bin/cql-explorer diff --git a/bin/docker-entry.sh b/bin/docker-entry.sh index 45b813e19..6c3e5835b 100755 --- a/bin/docker-entry.sh +++ b/bin/docker-entry.sh @@ -7,12 +7,12 @@ miner) exec /app/cql-minerd -config "${COVENANT_CONF}" "${@}" ;; blockproducer) - rm -f /app/node_*/chain.db exec /app/cqld -config "${COVENANT_CONF}" "${@}" ;; observer) - rm -f /app/node_observer/observer.db - exec /app/cql-observer -config "${COVENANT_CONF}" "${@}" + MAGIC_DOLLAR='$' envsubst < /etc/nginx/conf.d/servers/explorer.conf.template > /etc/nginx/conf.d/default.conf + nginx -g 'daemon off;' c.period { // TODO(leventeliu): add threshold config for `elapsed`. + log.WithFields(log.Fields{ + "advanced_height": c.getNextHeight(), + "using_timestamp": now.Format(time.RFC3339Nano), + "elapsed_seconds": elapsed.Seconds(), + }).Warn("too much time elapsed in the new period, skip this block") + return + } log.WithField("height", c.getNextHeight()).Info("producing a new block") if err := c.produceBlock(now); err != nil { log.WithField("now", now.Format(time.RFC3339Nano)).WithError(err).Errorln( @@ -512,11 +527,17 @@ func (c *Chain) mainCycle(ctx context.Context) { for { select { case <-timer.C: - c.syncCurrentHead(ctx) // Try to fetch block at height `nextHeight-1` + // Try to fetch block at height `nextHeight-1` until enough peers are reachable + if err := c.blockingSyncCurrentHead(ctx); err != nil { + log.WithError(err).Info("abort main cycle") + timer.Reset(0) + return + } + var t, d = c.nextTick() if d <= 0 { // Try to produce block at `nextHeight` if it's my turn, and increase height by 1 - c.advanceNextHeight(t) + c.advanceNextHeight(t, d) } else { log.WithFields(log.Fields{ "peer": c.peerInfo(), @@ -535,20 +556,64 @@ func (c *Chain) mainCycle(ctx context.Context) { } } -func (c *Chain) syncCurrentHead(ctx context.Context) { +func (c *Chain) blockingSyncCurrentHead(ctx context.Context) (err error) { + var ( + ticker *time.Ticker + interval = 1 * time.Second + ) + if c.tick < interval { + interval = c.tick + } + ticker = time.NewTicker(interval) + defer ticker.Stop() + for { + select { + case <-ticker.C: + if c.syncCurrentHead(ctx) { + return + } + case <-ctx.Done(): + err = ctx.Err() + return + } + } +} + +// syncCurrentHead synchronizes a block at the current height of the local peer from the known +// remote peers. The return value `ok` indicates that there're at less `c.confirms-1` replies +// from these gossip calls. +func (c *Chain) syncCurrentHead(ctx context.Context) (ok bool) { var h = c.getNextHeight() - 1 if c.head().height >= h { + ok = true return } // Initiate blocking gossip calls to fetch block of the current height, // with timeout of one tick. var ( - wg = &sync.WaitGroup{} - cld, ccl = context.WithTimeout(ctx, c.tick) + wg = &sync.WaitGroup{} + cld, ccl = context.WithTimeout(ctx, c.tick) + unreachable uint32 ) defer func() { wg.Wait() ccl() + var needConfirms, serversNum = func() (cf, sn uint32) { + c.RLock() + defer c.RUnlock() + cf, sn = c.confirms, c.serversNum + return + }() + if unreachable+needConfirms > serversNum { + log.WithFields(log.Fields{ + "peer": c.peerInfo(), + "sync_head_height": h, + "unreachable_count": unreachable, + }).Warn("one or more block producers are currently unreachable") + ok = false + } else { + ok = true + } }() for _, s := range c.getPeers().Servers { if !s.IsEqual(&c.nodeID) { @@ -565,23 +630,27 @@ func (c *Chain) syncCurrentHead(ctx context.Context) { } resp = &types.FetchBlockResp{} ) + var le = log.WithFields(log.Fields{ + "local": c.peerInfo(), + "remote": id, + "height": h, + }) if err = c.cl.CallNodeWithContext( cld, id, route.MCCFetchBlock.String(), req, resp, ); err != nil { - log.WithFields(log.Fields{ - "local": c.peerInfo(), - "remote": id, - "height": h, - }).WithError(err).Warn("failed to fetch block") + le.WithError(err).Warn("failed to fetch block") + atomic.AddUint32(&unreachable, 1) return } - log.WithFields(log.Fields{ - "local": c.peerInfo(), - "remote": id, - "height": h, + if resp.Block == nil { + le.Debug("fetch block request reply: no such block") + return + } + // Push new block from other peers + le.WithFields(log.Fields{ "parent": resp.Block.ParentHash().Short(4), "hash": resp.Block.BlockHash().Short(4), - }).Debug("fetched new block from remote peer") + }).Debug("fetch block request reply: found block") select { case c.pendingBlocks <- resp.Block: case <-cld.Done(): @@ -590,6 +659,7 @@ func (c *Chain) syncCurrentHead(ctx context.Context) { }(s) } } + return } func (c *Chain) storeTx(tx pi.Transaction) (err error) { @@ -782,6 +852,9 @@ func (c *Chain) applyBlock(bl *types.BPBlock) (err error) { // Return silently if block exists in the current branch return } + } + + for _, v := range c.branches { // Fork and create new branch if parent, ok = v.head.hasAncestorWithMinCount( bl.SignedHeader.ParentHash, c.lastIrre.count, diff --git a/blockproducer/chain_service.go b/blockproducer/chain_service.go index 0b94986b2..ea1187693 100644 --- a/blockproducer/chain_service.go +++ b/blockproducer/chain_service.go @@ -66,10 +66,12 @@ func (c *Chain) fetchLastIrreversibleBlock() ( func (c *Chain) fetchBlockByHeight(h uint32) (b *types.BPBlock, count uint32, err error) { var node = c.head().ancestor(h) + // Not found if node == nil { - err = ErrNoSuchBlock return - } else if node.block != nil { + } + // OK, and block is cached + if node.block != nil { b = node.block count = node.count return @@ -84,10 +86,12 @@ func (c *Chain) fetchBlockByHeight(h uint32) (b *types.BPBlock, count uint32, er func (c *Chain) fetchBlockByCount(count uint32) (b *types.BPBlock, height uint32, err error) { var node = c.head().ancestorByCount(count) + // Not found if node == nil { - err = ErrNoSuchBlock return - } else if node.block != nil { + } + // OK, and block is cached + if node.block != nil { b = node.block height = node.height return @@ -108,16 +112,10 @@ func (c *Chain) nextNonce(addr proto.AccountAddress) (n pi.AccountNonce, err err return } -func (c *Chain) loadAccountCovenantBalance(addr proto.AccountAddress) (balance uint64, ok bool) { - c.RLock() - defer c.RUnlock() - return c.immutable.loadAccountCovenantBalance(addr) -} - -func (c *Chain) loadAccountStableBalance(addr proto.AccountAddress) (balance uint64, ok bool) { +func (c *Chain) loadAccountTokenBalance(addr proto.AccountAddress, tt types.TokenType) (balance uint64, ok bool) { c.RLock() defer c.RUnlock() - return c.immutable.loadAccountStableBalance(addr) + return c.immutable.loadAccountTokenBalance(addr, tt) } func (c *Chain) loadSQLChainProfile(databaseID proto.DatabaseID) (profile *types.SQLChainProfile, ok bool) { diff --git a/blockproducer/chain_test.go b/blockproducer/chain_test.go index 857d668c6..1e4afe108 100644 --- a/blockproducer/chain_test.go +++ b/blockproducer/chain_test.go @@ -17,6 +17,7 @@ package blockproducer import ( + "fmt" "os" "path" "testing" @@ -232,6 +233,13 @@ func TestChain(t *testing.T) { f1.preview.commit() err = chain.pushBlock(bl) So(err, ShouldBeNil) + + Convey(fmt.Sprintf("Bug regression: duplicate branch #%d", i), func() { + var branchCount = len(chain.branches) + err = chain.pushBlock(bl) + So(err, ShouldBeNil) + So(branchCount, ShouldEqual, len(chain.branches)) + }) } Convey("The chain immutable should be updated to irreversible block", func() { @@ -284,11 +292,13 @@ func TestChain(t *testing.T) { count, height uint32 ) - _, _, err = chain.fetchBlockByHeight(100) - So(err, ShouldEqual, ErrNoSuchBlock) + bl, _, err = chain.fetchBlockByHeight(100) + So(bl, ShouldBeNil) + So(err, ShouldBeNil) - _, _, err = chain.fetchBlockByCount(100) - So(err, ShouldEqual, ErrNoSuchBlock) + bl, _, err = chain.fetchBlockByCount(100) + So(bl, ShouldBeNil) + So(err, ShouldBeNil) bl, count, err = chain.fetchBlockByHeight(0) So(err, ShouldBeNil) @@ -332,6 +342,7 @@ func TestChain(t *testing.T) { defer sv.Stop() chain.server = sv + chain.confirms = 1 chain.Start() defer func() { chain.Stop() diff --git a/blockproducer/errors.go b/blockproducer/errors.go index 29409bcd6..837b7e7ff 100644 --- a/blockproducer/errors.go +++ b/blockproducer/errors.go @@ -21,15 +21,6 @@ import "errors" var ( // ErrNoSuchDatabase defines database meta not exists error. ErrNoSuchDatabase = errors.New("no such database") - // ErrDatabaseAllocation defines database allocation failure error. - ErrDatabaseAllocation = errors.New("allocate database failed") - // ErrMetricNotCollected defines errors collected. - ErrMetricNotCollected = errors.New("metric not collected") - - // Errors on main chain - - // ErrCorruptedIndex defines index corrupted error. - ErrCorruptedIndex = errors.New("corrupted index item") // ErrParentNotFound defines that the parent block cannot be found. ErrParentNotFound = errors.New("previous block cannot be found") // ErrInvalidHash defines invalid hash error. @@ -40,19 +31,13 @@ var ( ErrInvalidMerkleTreeRoot = errors.New("Block merkle tree root does not match the tx hashes") // ErrParentNotMatch defines invalid parent hash. ErrParentNotMatch = errors.New("Block's parent hash cannot match best block") - // ErrNoSuchBlock defines no such block error. - ErrNoSuchBlock = errors.New("Cannot find such block") - // ErrNoSuchTxBilling defines no such txbilling error. - ErrNoSuchTxBilling = errors.New("Cannot find such txbilling") - // ErrSmallerSequenceID defines that new sequence id is smaller the old one. - ErrSmallerSequenceID = errors.New("SequanceID should be bigger than the old one") - // ErrInvalidBillingRequest defines BillingRequest is invalid - ErrInvalidBillingRequest = errors.New("The BillingRequest is invalid") // ErrBalanceOverflow indicates that there will be an overflow after balance manipulation. ErrBalanceOverflow = errors.New("balance overflow") // ErrInsufficientBalance indicates that an account has insufficient balance for spending. ErrInsufficientBalance = errors.New("insufficient balance") + // ErrInsufficientTransfer indicates that the transfer amount is insufficient for paying arrears. + ErrInsufficientTransfer = errors.New("insufficient transfer") // ErrAccountNotFound indicates that an account is not found. ErrAccountNotFound = errors.New("account not found") // ErrAccountExists indicates that the an account already exists. @@ -63,17 +48,11 @@ var ( ErrDatabaseExists = errors.New("database already exists") // ErrDatabaseUserExists indicates that the database user already exists. ErrDatabaseUserExists = errors.New("database user already exists") - // ErrDatabaseCannotCreate indicates that database cannot be created. - ErrDatabaseCannotCreate = errors.New("database cannot be created") // ErrInvalidAccountNonce indicates that a transaction has a invalid account nonce. ErrInvalidAccountNonce = errors.New("invalid account nonce") // ErrUnknownTransactionType indicates that a transaction has a unknown type and cannot be // further processed. ErrUnknownTransactionType = errors.New("unknown transaction type") - // ErrTransactionMismatch indicates that transactions to be committed mismatch the pool. - ErrTransactionMismatch = errors.New("transaction mismatch") - // ErrMetaStateNotFound indicates that meta state not found in db. - ErrMetaStateNotFound = errors.New("meta state not found in db") // ErrInvalidSender indicates that tx.Signee != tx.Sender. ErrInvalidSender = errors.New("invalid sender") // ErrNoSuchMiner indicates that this miner does not exist or register. @@ -82,6 +61,8 @@ var ( ErrNoEnoughMiner = errors.New("can not get enough miners") // ErrAccountPermissionDeny indicates that the sender does not own admin permission to the sqlchain. ErrAccountPermissionDeny = errors.New("account permission deny") + // ErrNoAdminLeft indicates there is no admin user in sqlchain. + ErrNoAdminLeft = errors.New("no admin user left") // ErrInvalidPermission indicates that the permission is invalid. ErrInvalidPermission = errors.New("invalid permission") // ErrMinerUserNotMatch indicates that the miner and user do not match. diff --git a/blockproducer/interfaces/mixins.go b/blockproducer/interfaces/mixins.go index 26cce6346..88ef8d353 100644 --- a/blockproducer/interfaces/mixins.go +++ b/blockproducer/interfaces/mixins.go @@ -16,11 +16,22 @@ package interfaces +import "time" + //go:generate hsp // TransactionTypeMixin provide type heuristic features to transaction wrapper. type TransactionTypeMixin struct { - TxType TransactionType + TxType TransactionType + Timestamp time.Time +} + +// NewTransactionTypeMixin returns new instance. +func NewTransactionTypeMixin(txType TransactionType) *TransactionTypeMixin { + return &TransactionTypeMixin{ + TxType: txType, + Timestamp: time.Now(), + } } // ContainsTransactionTypeMixin interface defines interface to detect transaction type mixin. @@ -38,9 +49,12 @@ func (m *TransactionTypeMixin) SetTransactionType(t TransactionType) { m.TxType = t } -// NewTransactionTypeMixin returns new instance. -func NewTransactionTypeMixin(txType TransactionType) *TransactionTypeMixin { - return &TransactionTypeMixin{ - TxType: txType, - } +// GetTimestamp implements Transaciton.GetTimestamp() +func (m *TransactionTypeMixin) GetTimestamp() time.Time { + return m.Timestamp +} + +// SetTimestamp is a helper function for derived types. +func (m *TransactionTypeMixin) SetTimestamp(t time.Time) { + m.Timestamp = t } diff --git a/blockproducer/interfaces/mixins_gen.go b/blockproducer/interfaces/mixins_gen.go index a3fb205a9..aa7b10d14 100644 --- a/blockproducer/interfaces/mixins_gen.go +++ b/blockproducer/interfaces/mixins_gen.go @@ -10,18 +10,20 @@ import ( func (z *TransactionTypeMixin) MarshalHash() (o []byte, err error) { var b []byte o = hsp.Require(b, z.Msgsize()) - // map header, size 1 - o = append(o, 0x81, 0x81) + // map header, size 2 + o = append(o, 0x82, 0x82) if oTemp, err := z.TxType.MarshalHash(); err != nil { return nil, err } else { o = hsp.AppendBytes(o, oTemp) } + o = append(o, 0x82) + o = hsp.AppendTime(o, z.Timestamp) return } // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *TransactionTypeMixin) Msgsize() (s int) { - s = 1 + 7 + z.TxType.Msgsize() + s = 1 + 7 + z.TxType.Msgsize() + 10 + hsp.TimeSize return } diff --git a/blockproducer/interfaces/mixins_test.go b/blockproducer/interfaces/mixins_test.go index 48fca8eb0..281d20e50 100644 --- a/blockproducer/interfaces/mixins_test.go +++ b/blockproducer/interfaces/mixins_test.go @@ -18,6 +18,7 @@ package interfaces import ( "testing" + "time" . "github.com/smartystreets/goconvey/convey" ) @@ -28,5 +29,9 @@ func TestTransactionTypeMixin(t *testing.T) { So(m.GetTransactionType(), ShouldEqual, TransactionTypeBaseAccount) m.SetTransactionType(TransactionTypeTransfer) So(m.GetTransactionType(), ShouldEqual, TransactionTypeTransfer) + now := time.Now() + So(now.Sub(m.GetTimestamp()).Seconds(), ShouldBeLessThan, 0.1) + m.SetTimestamp(now) + So(m.GetTimestamp(), ShouldEqual, now) }) } diff --git a/blockproducer/interfaces/transaction.go b/blockproducer/interfaces/transaction.go index bd936c414..35595d5c2 100644 --- a/blockproducer/interfaces/transaction.go +++ b/blockproducer/interfaces/transaction.go @@ -18,6 +18,7 @@ package interfaces import ( "encoding/binary" + "time" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" "github.com/CovenantSQL/CovenantSQL/crypto/hash" @@ -111,10 +112,11 @@ func (t TransactionType) String() string { // Transaction is the interface implemented by an object that can be verified and processed by // block producers. type Transaction interface { + GetTransactionType() TransactionType GetAccountAddress() proto.AccountAddress GetAccountNonce() AccountNonce + GetTimestamp() time.Time Hash() hash.Hash - GetTransactionType() TransactionType Sign(signer *asymmetric.PrivateKey) error Verify() error MarshalHash() ([]byte, error) diff --git a/blockproducer/metastate.go b/blockproducer/metastate.go index bb74b0937..1dfaf3891 100644 --- a/blockproducer/metastate.go +++ b/blockproducer/metastate.go @@ -18,6 +18,7 @@ package blockproducer import ( "bytes" + "sort" "time" pi "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" @@ -44,6 +45,20 @@ type metaState struct { dirty, readonly *metaIndex } +// MinerInfos is MinerInfo array +type MinerInfos []*types.MinerInfo + +// Len returns the length of the uints array. +func (x MinerInfos) Len() int { return len(x) } + +// Less returns true if MinerInfo i is less than node j. +func (x MinerInfos) Less(i, j int) bool { + return x[i].NodeID < x[j].NodeID +} + +// Swap exchanges MinerInfo i and j. +func (x MinerInfos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + func newMetaState() *metaState { return &metaState{ dirty: newMetaIndex(), @@ -52,13 +67,17 @@ func newMetaState() *metaState { } func (s *metaState) loadAccountObject(k proto.AccountAddress) (o *types.Account, loaded bool) { - if o, loaded = s.dirty.accounts[k]; loaded { - if o == nil { + var old *types.Account + if old, loaded = s.dirty.accounts[k]; loaded { + if old == nil { loaded = false + return } + o = deepcopy.Copy(old).(*types.Account) return } - if o, loaded = s.readonly.accounts[k]; loaded { + if old, loaded = s.readonly.accounts[k]; loaded { + o = deepcopy.Copy(old).(*types.Account) return } return @@ -77,43 +96,27 @@ func (s *metaState) loadOrStoreAccountObject( return } -func (s *metaState) loadAccountStableBalance(addr proto.AccountAddress) (b uint64, loaded bool) { - var o *types.Account - defer func() { - log.WithFields(log.Fields{ - "account": addr.String(), - "balance": b, - "loaded": loaded, - }).Debug("queried stable account") - }() - - if o, loaded = s.dirty.accounts[addr]; loaded && o != nil { - b = o.TokenBalance[types.Particle] +func (s *metaState) loadAccountTokenBalance(addr proto.AccountAddress, + tokenType types.TokenType) (b uint64, loaded bool) { + if !tokenType.Listed() { return } - if o, loaded = s.readonly.accounts[addr]; loaded { - b = o.TokenBalance[types.Particle] - return - } - return -} - -func (s *metaState) loadAccountCovenantBalance(addr proto.AccountAddress) (b uint64, loaded bool) { var o *types.Account defer func() { log.WithFields(log.Fields{ - "account": addr.String(), - "balance": b, - "loaded": loaded, - }).Debug("queried covenant account") + "account": addr.String(), + "balance": b, + "tokenType": tokenType.String(), + "loaded": loaded, + }).Debug("queried token account") }() if o, loaded = s.dirty.accounts[addr]; loaded && o != nil { - b = o.TokenBalance[types.Wave] + b = o.TokenBalance[tokenType] return } if o, loaded = s.readonly.accounts[addr]; loaded { - b = o.TokenBalance[types.Wave] + b = o.TokenBalance[tokenType] return } return @@ -260,7 +263,7 @@ func (s *metaState) increaseAccountToken(k proto.AccountAddress, amount uint64, ) if dst, ok = s.dirty.accounts[k]; !ok { if src, ok = s.readonly.accounts[k]; !ok { - err := errors.Wrap(ErrAccountNotFound, "increase stable balance fail") + err := errors.Wrap(ErrAccountNotFound, "increase account balance fail") return err } dst = deepcopy.Copy(src).(*types.Account) @@ -276,7 +279,7 @@ func (s *metaState) decreaseAccountToken(k proto.AccountAddress, amount uint64, ) if dst, ok = s.dirty.accounts[k]; !ok { if src, ok = s.readonly.accounts[k]; !ok { - err := errors.Wrap(ErrAccountNotFound, "increase stable balance fail") + err := errors.Wrap(ErrAccountNotFound, "decrease account balance fail") return err } dst = deepcopy.Copy(src).(*types.Account) @@ -307,6 +310,7 @@ func (s *metaState) transferAccountToken(transfer *types.Transfer) (err error) { err = errors.Wrapf(ErrInvalidSender, "applyTx failed: real sender %s, sender %s", realSender.String(), transfer.Sender.String()) log.WithError(err).Warning("public key not match sender in applyTransaction") + return } var ( @@ -641,7 +645,7 @@ func (s *metaState) matchProvidersWithUser(tx *types.CreateDatabase) (err error) return } - miners := make([]*types.MinerInfo, 0, minerCount) + miners := make(MinerInfos, 0, minerCount) for _, m := range tx.ResourceMeta.TargetMiners { if po, loaded := s.loadProviderObject(m); !loaded { @@ -669,28 +673,14 @@ func (s *metaState) matchProvidersWithUser(tx *types.CreateDatabase) (err error) err = errors.Wrapf(err, "miners match target are not enough %d:%d", len(miners), minerCount) return } - // try old miners first - for _, po := range s.readonly.provider { - miners, _ = filterAndAppendMiner(miners, po, tx, sender) - // if got enough, break - if uint64(len(miners)) == minerCount { - break - } - } - // try fresh miners - if uint64(len(miners)) < minerCount { - for _, po := range s.dirty.provider { - miners, _ = filterAndAppendMiner(miners, po, tx, sender) - // if got enough, break - if uint64(len(miners)) == minerCount { - break - } - } - } - if uint64(len(miners)) < minerCount { - err = ErrNoEnoughMiner + var newMiners MinerInfos + // create new merged map + newMiners, err = s.filterNMiners(tx, sender, int(minerCount)-len(miners)) + if err != nil { return } + + miners = append(miners, newMiners...) } // generate new sqlchain id and address @@ -747,7 +737,7 @@ func (s *metaState) matchProvidersWithUser(tx *types.CreateDatabase) (err error) Owner: sender, Users: users, EncodedGenesis: enc.Bytes(), - Miners: miners[:], + Miners: miners, } if _, loaded := s.loadSQLChainObject(dbID); loaded { @@ -756,13 +746,52 @@ func (s *metaState) matchProvidersWithUser(tx *types.CreateDatabase) (err error) } s.dirty.accounts[dbAddr] = &types.Account{Address: dbAddr} s.dirty.databases[dbID] = sp - for _, miner := range tx.ResourceMeta.TargetMiners { - s.deleteProviderObject(miner) + for _, miner := range miners { + s.deleteProviderObject(miner.Address) } log.Infof("success create sqlchain with database ID: %s", dbID) return } +func (s *metaState) filterNMiners( + tx *types.CreateDatabase, + user proto.AccountAddress, + minerCount int) ( + m MinerInfos, err error, +) { + // create new merged map + allProviderMap := make(map[proto.AccountAddress]*types.ProviderProfile) + for k, v := range s.readonly.provider { + allProviderMap[k] = v + } + for k, v := range s.dirty.provider { + if v == nil { + delete(allProviderMap, k) + } else { + allProviderMap[k] = v + } + } + + // delete selected target miners + for _, m := range tx.ResourceMeta.TargetMiners { + delete(allProviderMap, m) + } + + // suppose 1/4 miners match + newMiners := make(MinerInfos, 0, len(allProviderMap)/4) + // filter all miners to slice and sort + for _, po := range allProviderMap { + newMiners, _ = filterAndAppendMiner(newMiners, po, tx, user) + } + if len(newMiners) < minerCount { + err = ErrNoEnoughMiner + return + } + + sort.Slice(newMiners, newMiners.Less) + return newMiners[:minerCount], nil +} + func filterAndAppendMiner( miners []*types.MinerInfo, po *types.ProviderProfile, @@ -842,10 +871,6 @@ func (s *metaState) updatePermission(tx *types.UpdatePermission) (err error) { }).WithError(err).Error("unexpected err") return } - if sender == tx.TargetUser { - err = errors.Wrap(ErrInvalidSender, "user cannot update its permission by itself") - return - } so, loaded := s.loadSQLChainObject(tx.TargetSQLChain.DatabaseID()) if !loaded { log.WithFields(log.Fields{ @@ -863,9 +888,13 @@ func (s *metaState) updatePermission(tx *types.UpdatePermission) (err error) { // check whether sender is admin and find targetUser isAdmin := false + numOfAdmin := 0 targetUserIndex := -1 for i, u := range so.Users { isAdmin = isAdmin || (sender == u.Address && u.Permission == types.Admin) + if u.Permission == types.Admin { + numOfAdmin++ + } if tx.TargetUser == u.Address { targetUserIndex = i } @@ -879,12 +908,23 @@ func (s *metaState) updatePermission(tx *types.UpdatePermission) (err error) { return ErrAccountPermissionDeny } + // return error if number of Admin <= 1 and Admin want to revoke permission of itself + if numOfAdmin <= 1 && tx.TargetUser == sender && tx.Permission != types.Admin { + err = ErrNoAdminLeft + log.WithFields(log.Fields{ + "sender": sender.String(), + "dbID": tx.TargetSQLChain.String(), + "targetUser": tx.TargetUser.String(), + }).WithError(err).Warning("in updatePermission") + return + } + // update targetUser's permission if targetUserIndex == -1 { u := types.SQLChainUser{ Address: tx.TargetUser, Permission: tx.Permission, - Status: types.Normal, + Status: types.UnknownStatus, } so.Users = append(so.Users, &u) } else { @@ -939,7 +979,7 @@ func (s *metaState) updateBilling(tx *types.UpdateBilling) (err error) { err = errors.Wrap(ErrDatabaseNotFound, "update billing failed") return } - log.Debugf("update billing addr: %s, tx: %v", tx.GetAccountAddress(), tx) + log.Debugf("update billing addr: %s, user: %d, tx: %v", tx.GetAccountAddress(), len(tx.Users), tx) if newProfile.GasPrice == 0 { return @@ -958,7 +998,10 @@ func (s *metaState) updateBilling(tx *types.UpdateBilling) (err error) { } if !isMiner { err = ErrInvalidSender - log.WithError(err).Warning("sender does not include in sqlchain (updateBilling)") + log.WithFields(log.Fields{ + "miner_addr": minerAddr, + "miners": newProfile.Miners, + }).WithError(err).Warning("sender does not exists in sqlchain (updateBilling)") return } @@ -979,15 +1022,32 @@ func (s *metaState) updateBilling(tx *types.UpdateBilling) (err error) { miner.PendingIncome += userMap[user.Address][miner.Address] * newProfile.GasPrice } } else { - rate := 1 - float64(user.AdvancePayment)/float64(costMap[user.Address]*newProfile.GasPrice) + rate := float64(user.AdvancePayment) / float64(costMap[user.Address]*newProfile.GasPrice) user.AdvancePayment = 0 user.Status = types.Arrears for _, miner := range newProfile.Miners { income := userMap[user.Address][miner.Address] * newProfile.GasPrice minerIncome := uint64(float64(income) * rate) miner.PendingIncome += minerIncome + if miner.UserArrears == nil { + miner.UserArrears = make([]*types.UserArrears, 0) + } + exist := false for i := range miner.UserArrears { - miner.UserArrears[i].Arrears += (income - minerIncome) + if miner.UserArrears[i].User == user.Address { + exist = true + diff := income - minerIncome + miner.UserArrears[i].Arrears += diff + user.Arrears += diff + } + } + if !exist { + diff := income - minerIncome + miner.UserArrears = append(miner.UserArrears, &types.UserArrears{ + User: user.Address, + Arrears: diff, + }) + user.Arrears += diff } } } @@ -1017,29 +1077,82 @@ func (s *metaState) transferSQLChainTokenBalance(transfer *types.Transfer) (err realSender, err := crypto.PubKeyHash(transfer.Signee) if err != nil { err = errors.Wrap(err, "applyTx failed") - return err + return } if realSender != transfer.Sender { err = errors.Wrapf(ErrInvalidSender, "applyTx failed: real sender %s, sender %s", realSender.String(), transfer.Sender.String()) log.WithError(err).Warning("public key not match sender in applyTransaction") + return } var ( sqlchain *types.SQLChainProfile + account *types.Account ok bool ) - sqlchain, ok = s.loadSQLChainObject(transfer.Sender.DatabaseID()) + sqlchain, ok = s.loadSQLChainObject(transfer.Receiver.DatabaseID()) if !ok { - return ErrDatabaseNotFound + err = ErrDatabaseNotFound + log.WithFields(log.Fields{ + "dbid": transfer.Receiver.DatabaseID(), + "sender": transfer.Sender.String(), + }).WithError(err).Warning("database not exist in transferSQLChainTokenBalance") + return + } + if sqlchain.TokenType != transfer.TokenType { + err = ErrWrongTokenType + log.WithFields(log.Fields{ + "dbid": transfer.Receiver.DatabaseID(), + "sender": transfer.Sender.String(), + }).WithError(err).Warning("error token type in transferSQLChainTokenBalance") + return + } + account, ok = s.loadAccountObject(realSender) + if account.TokenBalance[transfer.TokenType] < transfer.Amount { + err = ErrInsufficientBalance + log.WithFields(log.Fields{ + "addr": account.Address.String(), + "amount": account.TokenBalance[transfer.TokenType], + "transfer_amount": transfer.Amount, + "token_type": transfer.TokenType.String(), + }).WithError(err).Warning("in transferSQLChainTokenBalance") + return } for _, user := range sqlchain.Users { if user.Address == transfer.Sender { - if sqlchain.TokenType != transfer.TokenType { - return ErrWrongTokenType + // process arrears + if user.Arrears > 0 { + if user.Arrears <= transfer.Amount { + for _, miner := range sqlchain.Miners { + newUserArrears := make([]*types.UserArrears, len(miner.UserArrears)) + i := 0 + for _, ua := range miner.UserArrears { + if ua.User == user.Address { + miner.PendingIncome += miner.UserArrears[i].Arrears + } else { + newUserArrears[i] = ua + i++ + } + } + } + user.Arrears = 0 + user.Status = types.Normal + + transfer.Amount -= user.Arrears + account.TokenBalance[transfer.TokenType] -= user.Arrears + } else { + err = ErrInsufficientTransfer + log.WithFields(log.Fields{ + "arrears": user.Arrears, + "transfer_amount": transfer.Amount, + }).WithError(err).Warning("in transferSQLChainTokenBalance") + return + } } + minDep := minDeposit(sqlchain.GasPrice, uint64(len(sqlchain.Miners))) if user.Deposit < minDep { diff := minDep - user.Deposit @@ -1048,15 +1161,22 @@ func (s *metaState) transferSQLChainTokenBalance(transfer *types.Transfer) (err } else { user.Deposit = minDep diff2 := transfer.Amount - diff - user.Deposit += diff2 + user.AdvancePayment += diff2 } } else { err = safeAdd(&user.AdvancePayment, &transfer.Amount) if err != nil { - return err + return + } + } + account.TokenBalance[transfer.TokenType] -= transfer.Amount + if !user.Status.EnableQuery() { + if user.AdvancePayment > minDep { + user.Status = types.Normal } } - s.dirty.databases[transfer.Sender.DatabaseID()] = sqlchain + s.dirty.databases[transfer.Receiver.DatabaseID()] = sqlchain + s.dirty.accounts[realSender] = account return } } @@ -1168,5 +1288,5 @@ func (s *metaState) makeCopy() *metaState { func minDeposit(gasPrice uint64, minerNumber uint64) uint64 { return gasPrice * uint64(conf.GConf.QPS) * - uint64(conf.GConf.BillingPeriod) * minerNumber + conf.GConf.BillingBlockCount * minerNumber } diff --git a/blockproducer/metastate_test.go b/blockproducer/metastate_test.go index 53ed86379..f6bca9ac2 100644 --- a/blockproducer/metastate_test.go +++ b/blockproducer/metastate_test.go @@ -31,6 +31,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" "github.com/CovenantSQL/CovenantSQL/types" + "github.com/CovenantSQL/CovenantSQL/utils/log" "github.com/pkg/errors" . "github.com/smartystreets/goconvey/convey" ) @@ -81,9 +82,9 @@ func TestMetaState(t *testing.T) { ao, loaded = ms.loadAccountObject(addr1) So(ao, ShouldBeNil) So(loaded, ShouldBeFalse) - bl, loaded = ms.loadAccountStableBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeFalse) - bl, loaded = ms.loadAccountCovenantBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Wave) So(loaded, ShouldBeFalse) }) Convey("The database state should be empty", func() { @@ -154,10 +155,10 @@ func TestMetaState(t *testing.T) { So(loaded, ShouldBeTrue) So(co, ShouldNotBeNil) So(co.ID, ShouldEqual, dbID1) - bl, loaded = ms.loadAccountStableBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, 0) - bl, loaded = ms.loadAccountCovenantBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Wave) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, 0) }) @@ -273,10 +274,10 @@ func TestMetaState(t *testing.T) { So(ao.Address, ShouldEqual, addr1) So(ao.TokenBalance[types.Particle], ShouldEqual, incSta) So(ao.TokenBalance[types.Wave], ShouldEqual, incCov) - bl, loaded = ms.loadAccountStableBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, incSta) - bl, loaded = ms.loadAccountCovenantBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Wave) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, incCov) }) @@ -302,10 +303,10 @@ func TestMetaState(t *testing.T) { Convey( "The account balance should be kept correctly in account object", func() { - bl, loaded = ms.loadAccountStableBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, incSta) - bl, loaded = ms.loadAccountCovenantBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Wave) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, incCov) }, @@ -593,10 +594,10 @@ func TestMetaState(t *testing.T) { } ms.commit() Convey("The state should match the update result", func() { - bl, loaded = ms.loadAccountStableBalance(addr1) + bl, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, 84) - bl, loaded = ms.loadAccountStableBalance(addr2) + bl, loaded = ms.loadAccountTokenBalance(addr2, types.Particle) So(loaded, ShouldBeTrue) So(bl, ShouldEqual, 118) }) @@ -633,19 +634,25 @@ func TestMetaState(t *testing.T) { types.NewBaseAccount( &types.Account{ Address: addr1, - TokenBalance: [types.SupportTokenNumber]uint64{10000000, 100}, + TokenBalance: [types.SupportTokenNumber]uint64{1000000000, 1000000000}, }, ), types.NewBaseAccount( &types.Account{ Address: addr2, - TokenBalance: [types.SupportTokenNumber]uint64{10000000, 100}, + TokenBalance: [types.SupportTokenNumber]uint64{10000000000, 100}, }, ), types.NewBaseAccount( &types.Account{ Address: addr3, - TokenBalance: [types.SupportTokenNumber]uint64{100000, 100}, + TokenBalance: [types.SupportTokenNumber]uint64{10000, 10000}, + }, + ), + types.NewBaseAccount( + &types.Account{ + Address: addr4, + TokenBalance: [types.SupportTokenNumber]uint64{1000000000, 1000000000}, }, ), } @@ -656,6 +663,9 @@ func TestMetaState(t *testing.T) { err = txs[1].Sign(privKey2) So(err, ShouldBeNil) err = txs[2].Sign(privKey3) + So(err, ShouldBeNil) + err = txs[3].Sign(privKey4) + So(err, ShouldBeNil) for i := range txs { err = ms.apply(txs[i]) So(err, ShouldBeNil) @@ -689,7 +699,7 @@ func TestMetaState(t *testing.T) { Node: 1, }, GasPrice: 1, - AdvancePayment: uint64(conf.GConf.QPS) * uint64(conf.GConf.BillingPeriod) * 1, + AdvancePayment: uint64(conf.GConf.QPS) * conf.GConf.BillingBlockCount * 1, TokenType: types.Particle, Nonce: 1, }, @@ -731,7 +741,7 @@ func TestMetaState(t *testing.T) { }, Nonce: 1, GasPrice: 1, - AdvancePayment: uint64(conf.GConf.QPS) * uint64(conf.GConf.BillingPeriod) * 2, + AdvancePayment: uint64(conf.GConf.QPS) * conf.GConf.BillingBlockCount * 2, }, } err = invalidCd5.Sign(privKey3) @@ -745,7 +755,7 @@ func TestMetaState(t *testing.T) { }, Nonce: 1, GasPrice: 1, - AdvancePayment: uint64(conf.GConf.QPS) * uint64(conf.GConf.BillingPeriod) * 1, + AdvancePayment: uint64(conf.GConf.QPS) * conf.GConf.BillingBlockCount * 1, }, } err = invalidCd6.Sign(privKey3) @@ -755,7 +765,7 @@ func TestMetaState(t *testing.T) { Owner: addr3, ResourceMeta: types.ResourceMeta{ TargetMiners: []proto.AccountAddress{addr2}, - Node: 10, + Node: 2, Space: 9, Memory: 9, LoadAvgPerCPU: 0.1, @@ -764,11 +774,30 @@ func TestMetaState(t *testing.T) { }, Nonce: 1, GasPrice: 1, - AdvancePayment: uint64(conf.GConf.QPS) * uint64(conf.GConf.BillingPeriod) * 10, + AdvancePayment: uint64(conf.GConf.QPS) * conf.GConf.BillingBlockCount * 2, }, } err = invalidCd7.Sign(privKey3) So(err, ShouldBeNil) + invalidCd8 := types.CreateDatabase{ + CreateDatabaseHeader: types.CreateDatabaseHeader{ + Owner: addr2, + ResourceMeta: types.ResourceMeta{ + TargetMiners: []proto.AccountAddress{addr2}, + Node: 2, + Space: 9, + Memory: 9, + LoadAvgPerCPU: 0.1, + UseEventualConsistency: false, + ConsistencyLevel: 0, + }, + Nonce: 1, + GasPrice: 1, + AdvancePayment: uint64(conf.GConf.QPS) * uint64(conf.GConf.BillingBlockCount) * 2, + }, + } + err = invalidCd8.Sign(privKey2) + So(err, ShouldBeNil) err = ms.apply(&invalidPs) So(errors.Cause(err), ShouldEqual, ErrInsufficientBalance) @@ -833,6 +862,63 @@ func TestMetaState(t *testing.T) { } err = ms.apply(&invalidCd7) So(errors.Cause(err), ShouldEqual, ErrNoEnoughMiner) + + ms.readonly.provider[proto.AccountAddress(hash.HashH([]byte("9")))] = &types.ProviderProfile{ + TargetUser: []proto.AccountAddress{addr2}, + GasPrice: 1, + LoadAvgPerCPU: 0.001, + Memory: 100, + Space: 100, + TokenType: 0, + NodeID: "0001111", + } + ms.dirty.provider[proto.AccountAddress(hash.HashH([]byte("9")))] = &types.ProviderProfile{ + TargetUser: []proto.AccountAddress{addr2}, + GasPrice: 1, + LoadAvgPerCPU: 0.001, + Memory: 100, + Space: 100, + TokenType: 0, + NodeID: "0002111", + } + ms.dirty.provider[proto.AccountAddress(hash.HashH([]byte("10")))] = &types.ProviderProfile{ + TargetUser: []proto.AccountAddress{addr2}, + GasPrice: 1, + LoadAvgPerCPU: 0.001, + Memory: 100, + Space: 100, + TokenType: 0, + NodeID: "0003111", + } + ms.dirty.provider[proto.AccountAddress(hash.HashH([]byte("11")))] = &types.ProviderProfile{ + TargetUser: []proto.AccountAddress{addr2}, + GasPrice: 1, + LoadAvgPerCPU: 0.001, + Memory: 100, + Space: 100, + TokenType: 0, + NodeID: "0000003", + } + ms.dirty.provider[proto.AccountAddress(hash.HashH([]byte("12")))] = &types.ProviderProfile{ + TargetUser: []proto.AccountAddress{addr2}, + GasPrice: 1, + LoadAvgPerCPU: 0.001, + Memory: 100, + Space: 100, + TokenType: 0, + NodeID: "0000001", + } + err = ms.apply(&invalidCd8) + So(err, ShouldBeNil) + dbID := proto.FromAccountAndNonce(addr2, uint32(invalidCd8.Nonce)) + + mIDs := make([]string, 0) + for _, m := range ms.dirty.databases[dbID].Miners { + mIDs = append(mIDs, string(m.NodeID)) + } + log.Debugf("mIDs: %v", mIDs) + So(mIDs, ShouldContain, "0000003") + So(mIDs, ShouldContain, "0000001") }) Convey("When SQLChain create", func() { ps := types.ProvideService{ @@ -877,24 +963,24 @@ func TestMetaState(t *testing.T) { So(err, ShouldBeNil) var b1, b2 uint64 - b1, loaded = ms.loadAccountStableBalance(addr2) + b1, loaded = ms.loadAccountTokenBalance(addr2, types.Particle) err = ms.apply(&ps) So(err, ShouldBeNil) ms.commit() - b2, loaded = ms.loadAccountStableBalance(addr2) + b2, loaded = ms.loadAccountTokenBalance(addr2, types.Particle) So(loaded, ShouldBeTrue) So(b1-b2, ShouldEqual, conf.GConf.MinProviderDeposit) err = ms.apply(&cd2) So(errors.Cause(err), ShouldEqual, ErrMinerUserNotMatch) - b1, loaded = ms.loadAccountStableBalance(addr1) + b1, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) err = ms.apply(&cd1) So(err, ShouldBeNil) ms.commit() - b2, loaded = ms.loadAccountStableBalance(addr1) + b2, loaded = ms.loadAccountTokenBalance(addr1, types.Particle) So(loaded, ShouldBeTrue) minAdvancePayment := uint64(cd2.GasPrice) * uint64(conf.GConf.QPS) * - uint64(conf.GConf.BillingPeriod) * uint64(len(cd2.ResourceMeta.TargetMiners)) + conf.GConf.BillingBlockCount * uint64(len(cd2.ResourceMeta.TargetMiners)) So(b1-b2, ShouldEqual, cd1.AdvancePayment+minAdvancePayment) dbID := proto.FromAccountAndNonce(cd1.Owner, uint32(cd1.Nonce)) co, loaded = ms.loadSQLChainObject(dbID) @@ -953,7 +1039,7 @@ func TestMetaState(t *testing.T) { err = up.Sign(privKey3) So(err, ShouldBeNil) err = ms.apply(&up) - So(errors.Cause(err), ShouldEqual, ErrInvalidSender) + So(errors.Cause(err), ShouldEqual, ErrNoAdminLeft) // addr1(read) update addr3(admin) fail up.Nonce = cd1.Nonce + 2 err = up.Sign(privKey1) @@ -976,6 +1062,145 @@ func TestMetaState(t *testing.T) { continue } } + Convey("transfer token", func() { + addr1B1, ok := ms.loadAccountTokenBalance(addr1, types.Particle) + So(ok, ShouldBeTrue) + addr3B1, ok := ms.loadAccountTokenBalance(addr3, types.Particle) + So(ok, ShouldBeTrue) + trans1 := types.NewTransfer(&types.TransferHeader{ + Sender: addr1, + Receiver: addr3, + Amount: 20000000, + TokenType: types.Particle, + }) + nonce, err := ms.nextNonce(addr1) + So(err, ShouldBeNil) + trans1.Nonce = nonce + err = trans1.Sign(privKey1) + So(err, ShouldBeNil) + err = ms.apply(trans1) + So(err, ShouldBeNil) + ms.commit() + addr1B2, ok := ms.loadAccountTokenBalance(addr1, types.Particle) + So(ok, ShouldBeTrue) + addr3B2, ok := ms.loadAccountTokenBalance(addr3, types.Particle) + So(ok, ShouldBeTrue) + So(addr1B1-addr1B2, ShouldEqual, 20000000) + So(addr3B2-addr3B1, ShouldEqual, 20000000) + profile, ok := ms.loadSQLChainObject(dbID) + So(ok, ShouldBeTrue) + + // transfer to sqlchain + for _, user := range profile.Users { + if user.Address == addr3 { + So(user.Status, ShouldEqual, types.UnknownStatus) + break + } + } + trans2 := types.NewTransfer(&types.TransferHeader{ + Sender: addr3, + Receiver: dbAccount, + Amount: 8000000, + TokenType: types.Particle, + }) + nonce, err = ms.nextNonce(addr3) + So(err, ShouldBeNil) + So(dbID, ShouldEqual, dbAccount.DatabaseID()) + trans2.Nonce = nonce + err = trans2.Sign(privKey3) + So(err, ShouldBeNil) + err = ms.apply(trans2) + So(err, ShouldBeNil) + // ms.commit() + profile, ok = ms.loadSQLChainObject(dbID) + So(ok, ShouldBeTrue) + for _, user := range profile.Users { + if user.Address == addr3 { + So(user.Status, ShouldEqual, types.Normal) + break + } + } + + // make addr3 arrears + ub := types.NewUpdateBilling(&types.UpdateBillingHeader{ + Receiver: dbAccount, + Users: []*types.UserCost{ + &types.UserCost{ + User: addr3, + Cost: 4500000, + Miners: []*types.MinerIncome{ + &types.MinerIncome{ + Miner: addr2, + Income: 4500000, + }, + }, + }, + }, + }) + nonce, err = ms.nextNonce(addr2) + So(err, ShouldBeNil) + ub.Nonce = nonce + err = ub.Sign(privKey2) + So(err, ShouldBeNil) + err = ms.apply(ub) + So(err, ShouldBeNil) + ms.commit() + profile, ok = ms.loadSQLChainObject(dbID) + So(ok, ShouldBeTrue) + for _, user := range profile.Users { + if user.Address == addr3 { + So(user.Status, ShouldEqual, types.Arrears) + break + } + } + + // transfer failed + trans3 := types.NewTransfer(&types.TransferHeader{ + Sender: addr3, + Receiver: dbAccount, + Amount: 40000, + TokenType: types.Particle, + }) + nonce, err = ms.nextNonce(addr3) + So(err, ShouldBeNil) + trans3.Nonce = nonce + err = trans3.Sign(privKey3) + So(err, ShouldBeNil) + err = ms.apply(trans3) + So(err, ShouldEqual, ErrInsufficientTransfer) + profile, ok = ms.loadSQLChainObject(dbID) + So(ok, ShouldBeTrue) + for _, user := range profile.Users { + if user.Address == addr3 { + So(user.Status, ShouldEqual, types.Arrears) + break + } + } + + // transfer enough token + trans4 := types.NewTransfer(&types.TransferHeader{ + Sender: addr3, + Receiver: dbAccount, + Amount: 4000000, + TokenType: types.Particle, + }) + nonce, err = ms.nextNonce(addr3) + So(err, ShouldBeNil) + trans4.Nonce = nonce + err = trans4.Sign(privKey3) + So(err, ShouldBeNil) + err = ms.apply(trans4) + ms.commit() + profile, ok = ms.loadSQLChainObject(dbID) + So(ok, ShouldBeTrue) + for _, user := range profile.Users { + if user.Address == addr3 { + So(user.Status, ShouldEqual, types.Normal) + break + } + } + + }) Convey("update key", func() { invalidIk1 := &types.IssueKeys{} err = invalidIk1.Sign(privKey1) @@ -1050,6 +1275,49 @@ func TestMetaState(t *testing.T) { So(err, ShouldBeNil) err = ms.apply(ub1) So(errors.Cause(err), ShouldEqual, ErrDatabaseNotFound) + trans1 := types.NewTransfer(&types.TransferHeader{ + Sender: addr1, + Receiver: dbAccount, + Amount: 8000000, + TokenType: types.Particle, + }) + nonce, err := ms.nextNonce(addr1) + So(err, ShouldBeNil) + trans1.Nonce = nonce + err = trans1.Sign(privKey1) + So(err, ShouldBeNil) + err = ms.apply(trans1) + So(err, ShouldBeNil) + ms.commit() + trans2 := types.NewTransfer(&types.TransferHeader{ + Sender: addr3, + Receiver: dbAccount, + Amount: 800, + TokenType: types.Particle, + }) + nonce, err = ms.nextNonce(addr3) + So(err, ShouldBeNil) + trans2.Nonce = nonce + err = trans2.Sign(privKey3) + So(err, ShouldBeNil) + err = ms.apply(trans2) + So(err, ShouldBeNil) + ms.commit() + trans3 := types.NewTransfer(&types.TransferHeader{ + Sender: addr4, + Receiver: dbAccount, + Amount: 8000000, + TokenType: types.Particle, + }) + nonce, err = ms.nextNonce(addr4) + So(err, ShouldBeNil) + trans3.Nonce = nonce + err = trans3.Sign(privKey4) + So(err, ShouldBeNil) + err = ms.apply(trans3) + So(err, ShouldBeNil) + ms.commit() + users := [3]*types.UserCost{ &types.UserCost{ User: addr1, @@ -1096,7 +1364,7 @@ func TestMetaState(t *testing.T) { sqlchain, loaded := ms.loadSQLChainObject(dbID) So(loaded, ShouldBeTrue) So(len(sqlchain.Miners), ShouldEqual, 1) - So(sqlchain.Miners[0].PendingIncome, ShouldEqual, 125) + So(sqlchain.Miners[0].PendingIncome, ShouldEqual, 115) users = [3]*types.UserCost{ &types.UserCost{ User: addr1, @@ -1144,7 +1412,7 @@ func TestMetaState(t *testing.T) { So(loaded, ShouldBeTrue) So(len(sqlchain.Miners), ShouldEqual, 1) So(sqlchain.Miners[0].PendingIncome, ShouldEqual, 115) - So(sqlchain.Miners[0].ReceivedIncome, ShouldEqual, 125) + So(sqlchain.Miners[0].ReceivedIncome, ShouldEqual, 115) }) }) }) diff --git a/blockproducer/rpc.go b/blockproducer/rpc.go index 7de2dfdaa..dd244bd9d 100644 --- a/blockproducer/rpc.go +++ b/blockproducer/rpc.go @@ -109,21 +109,12 @@ func (s *ChainRPCService) AddTx(req *types.AddTxReq, resp *types.AddTxResp) (err return } -// QueryAccountStableBalance is the RPC method to query account stable coin balance. -func (s *ChainRPCService) QueryAccountStableBalance( - req *types.QueryAccountStableBalanceReq, resp *types.QueryAccountStableBalanceResp) (err error, +// QueryAccountTokenBalance is the RPC method to query account token balance. +func (s *ChainRPCService) QueryAccountTokenBalance( + req *types.QueryAccountTokenBalanceReq, resp *types.QueryAccountTokenBalanceResp) (err error, ) { resp.Addr = req.Addr - resp.Balance, resp.OK = s.chain.loadAccountStableBalance(req.Addr) - return -} - -// QueryAccountCovenantBalance is the RPC method to query account covenant coin balance. -func (s *ChainRPCService) QueryAccountCovenantBalance( - req *types.QueryAccountCovenantBalanceReq, resp *types.QueryAccountCovenantBalanceResp) (err error, -) { - resp.Addr = req.Addr - resp.Balance, resp.OK = s.chain.loadAccountCovenantBalance(req.Addr) + resp.Balance, resp.OK = s.chain.loadAccountTokenBalance(req.Addr, req.TokenType) return } @@ -154,23 +145,17 @@ func WaitDatabaseCreation( period time.Duration, ) (err error) { var ( - timer = time.NewTimer(0) - req = &types.QuerySQLChainProfileReq{ + ticker = time.NewTicker(period) + req = &types.QuerySQLChainProfileReq{ DBID: dbID, } - resp = &types.QuerySQLChainProfileResp{} ) - defer func() { - if !timer.Stop() { - <-timer.C - } - }() + defer ticker.Stop() for { select { - case <-timer.C: - timer.Reset(period) + case <-ticker.C: if err = rpc.RequestBP( - route.MCCQuerySQLChainProfile.String(), req, resp, + route.MCCQuerySQLChainProfile.String(), req, nil, ); err != nil { if !strings.Contains(err.Error(), ErrDatabaseNotFound.Error()) { // err != nil && err != ErrDatabaseNotFound (unexpected error) @@ -193,6 +178,30 @@ func WaitDatabaseCreation( } } +// WaitBPChainService waits until BP chain service is ready. +func WaitBPChainService(ctx context.Context, period time.Duration) (err error) { + var ( + ticker = time.NewTicker(period) + req = &types.FetchBlockReq{ + Height: 0, // Genesis block + } + ) + defer ticker.Stop() + for { + select { + case <-ticker.C: + if err = rpc.RequestBP( + route.MCCFetchBlock.String(), req, nil, + ); err == nil || !strings.Contains(err.Error(), "can't find service") { + return + } + case <-ctx.Done(): + err = ctx.Err() + return + } + } +} + // Create allocates new database. func Create( meta types.ResourceMeta, diff --git a/blockproducer/storage.go b/blockproducer/storage.go index 8f2e9242c..344772682 100644 --- a/blockproducer/storage.go +++ b/blockproducer/storage.go @@ -81,6 +81,7 @@ func store(st xi.Storage, sps []storageProcedure, cb storageCallback) (err error if tx, err = st.Writer().Begin(); err != nil { return } + log.Debugf("started database tx %p", tx) // ROLLBACK on failure defer tx.Rollback() // WRITE @@ -92,11 +93,13 @@ func store(st xi.Storage, sps []storageProcedure, cb storageCallback) (err error // CALLBACK: MUST NOT FAIL if cb != nil { cb() + log.Debugf("invoked storage callback %p in tx %p", cb, tx) } // COMMIT if err = tx.Commit(); err != nil { log.WithError(err).Fatal("failed to commit storage transaction") } + log.Debugf("committed database tx %p", tx) return } @@ -194,6 +197,11 @@ func updateAccount(account *types.Account) storageProcedure { return errPass(err) } return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "account_address": account.Address.String(), + "account_nonce": account.NextNonce, + "account_balances": account.TokenBalance, + }).Debug("updating account") _, err = tx.Exec(`INSERT OR REPLACE INTO "accounts" ("address", "encoded") VALUES (?, ?)`, account.Address.String(), @@ -204,6 +212,9 @@ func updateAccount(account *types.Account) storageProcedure { func deleteAccount(address proto.AccountAddress) storageProcedure { return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "account_address": address.String(), + }).Debug("deleting account") _, err = tx.Exec(`DELETE FROM "accounts" WHERE "address"=?`, address.String()) return } @@ -218,6 +229,13 @@ func updateShardChain(profile *types.SQLChainProfile) storageProcedure { return errPass(err) } return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "profile_owner": profile.Owner.String(), + "profile_address": profile.Address.String(), + "profile_database_id": profile.ID, + "profile_token_type": profile.TokenType, + "profile_miners_number": len(profile.Miners), + }).Debug("updating profile") _, err = tx.Exec(`INSERT OR REPLACE INTO "shardChain" ("address", "id", "encoded") VALUES (?, ?, ?)`, profile.Address.String(), @@ -229,6 +247,9 @@ func updateShardChain(profile *types.SQLChainProfile) storageProcedure { func deleteShardChain(id proto.DatabaseID) storageProcedure { return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "profile_database_id": id, + }).Debug("deleting profile") _, err = tx.Exec(`DELETE FROM "shardChain" WHERE "id"=?`, id) return } @@ -243,6 +264,11 @@ func updateProvider(profile *types.ProviderProfile) storageProcedure { return errPass(err) } return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "provider_address": profile.Provider.String(), + "provider_token_type": profile.TokenType, + "provider_node_id": profile.NodeID, + }).Debug("updating provider") _, err = tx.Exec(`INSERT OR REPLACE INTO "provider" ("address", "encoded") VALUES (?, ?)`, profile.Provider.String(), enc.Bytes()) @@ -252,6 +278,9 @@ func updateProvider(profile *types.ProviderProfile) storageProcedure { func deleteProvider(address proto.AccountAddress) storageProcedure { return func(tx *sql.Tx) (err error) { + log.WithFields(log.Fields{ + "provider_address": address.String(), + }).Debug("deleting provider") _, err = tx.Exec(`DELETE FROM "provider" WHERE "address"=?`, address.String()) return } diff --git a/blockproducer/xxx_test.go b/blockproducer/xxx_test.go index 2b5d919e1..f254d9d90 100644 --- a/blockproducer/xxx_test.go +++ b/blockproducer/xxx_test.go @@ -21,454 +21,30 @@ import ( "math/rand" "os" "path" - "sync" "testing" "time" - pi "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" "github.com/CovenantSQL/CovenantSQL/conf" - "github.com/CovenantSQL/CovenantSQL/crypto" ca "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/crypto/kms" - "github.com/CovenantSQL/CovenantSQL/pow/cpuminer" - "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" - "github.com/CovenantSQL/CovenantSQL/types" "github.com/CovenantSQL/CovenantSQL/utils/log" ) var ( - genesisHash = hash.Hash{} - uuidLen = 32 - peerNum uint32 = 32 - - testAddress1 = proto.AccountAddress{0x0, 0x0, 0x0, 0x1} - testAddress2 = proto.AccountAddress{0x0, 0x0, 0x0, 0x2} - testInitBalance = uint64(10000) - testDifficulty = 4 - - testAddress1Nonce pi.AccountNonce + genesisHash = hash.Hash{} testingDataDir string - testingTraceFile *os.File testingConfigFile = "../test/node_standalone/config.yaml" testingPrivateKeyFile = "../test/node_standalone/private.key" testingPublicKeyStoreFile string testingNonceDifficulty int - - testingPrivateKey *ca.PrivateKey - testingPublicKey *ca.PublicKey - - testingMasterKey = []byte(`?08Rl%WUih4V0H+c`) + testingPrivateKey *ca.PrivateKey + testingPublicKey *ca.PublicKey ) -const ( - letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -) - -func generateRandomBytes(n int32) []byte { - s := make([]byte, n) - for i := range s { - s[i] = byte(rand.Int31n(2)) - } - return s -} - -func generateRandomDatabaseID() *proto.DatabaseID { - id := proto.DatabaseID(randStringBytes(uuidLen)) - return &id -} - -func generateRandomDatabaseIDs(n int32) []proto.DatabaseID { - s := make([]proto.DatabaseID, n) - for i := range s { - s[i] = proto.DatabaseID(randStringBytes(uuidLen)) - } - return s -} - -func randStringBytes(n int) string { - b := make([]byte, n) - for i := range b { - b[i] = letterBytes[rand.Intn(len(letterBytes))] - } - return string(b) -} - -func generateRandomBlock(parent hash.Hash, isGenesis bool) (b *types.BPBlock, err error) { - // Generate key pair - priv, _, err := ca.GenSecp256k1KeyPair() - - if err != nil { - return - } - - h := hash.Hash{} - rand.Read(h[:]) - - b = &types.BPBlock{ - SignedHeader: types.BPSignedHeader{ - BPHeader: types.BPHeader{ - Version: 0x01000000, - Producer: proto.AccountAddress(h), - ParentHash: parent, - Timestamp: time.Now().UTC(), - }, - }, - } - - if !isGenesis { - for i, n := 0, rand.Intn(10)+10; i < n; i++ { - ba, tb, err := generateRandomBillingAndBaseAccount() - if err != nil { - return nil, err - } - b.Transactions = append(b.Transactions, ba, tb) - } - } else { - // Create base accounts - var ( - ba1 = types.NewBaseAccount( - &types.Account{ - Address: testAddress1, - TokenBalance: [types.SupportTokenNumber]uint64{testInitBalance, testInitBalance}, - }, - ) - ba2 = types.NewBaseAccount( - &types.Account{ - Address: testAddress2, - TokenBalance: [types.SupportTokenNumber]uint64{testInitBalance, testInitBalance}, - }, - ) - ) - if err = ba1.Sign(testingPrivateKey); err != nil { - return - } - if err = ba2.Sign(testingPrivateKey); err != nil { - return - } - b.Transactions = append(b.Transactions, ba1, ba2) - } - - err = b.PackAndSignBlock(priv) - return -} - -func generateRandomBlockWithTransactions(parent hash.Hash, tbs []pi.Transaction) (b *types.BPBlock, err error) { - // Generate key pair - priv, _, err := ca.GenSecp256k1KeyPair() - - if err != nil { - return - } - - h := hash.Hash{} - rand.Read(h[:]) - - b = &types.BPBlock{ - SignedHeader: types.BPSignedHeader{ - BPHeader: types.BPHeader{ - Version: 0x01000000, - Producer: proto.AccountAddress(h), - ParentHash: parent, - Timestamp: time.Now().UTC(), - }, - }, - } - - for _, tb := range tbs { - b.Transactions = append(b.Transactions, tb) - } - - testAddress1Nonce++ - var tr = types.NewTransfer( - &types.TransferHeader{ - Sender: testAddress1, - Receiver: testAddress2, - Nonce: testAddress1Nonce, - Amount: 1, - }, - ) - if err = tr.Sign(priv); err != nil { - return - } - b.Transactions = append(b.Transactions, tr) - - err = b.PackAndSignBlock(priv) - - return -} - -func generateRandomBillingRequestHeader() *types.BillingRequestHeader { - return &types.BillingRequestHeader{ - DatabaseID: *generateRandomDatabaseID(), - LowBlock: generateRandomHash(), - LowHeight: rand.Int31(), - HighBlock: generateRandomHash(), - HighHeight: rand.Int31(), - GasAmounts: generateRandomGasAmount(peerNum), - } -} - -func generateRandomBillingRequest() (*types.BillingRequest, error) { - reqHeader := generateRandomBillingRequestHeader() - req := types.BillingRequest{ - Header: *reqHeader, - } - h, err := req.PackRequestHeader() - if err != nil { - return nil, err - } - - signees := make([]*ca.PublicKey, peerNum) - signatures := make([]*ca.Signature, peerNum) - - for i := range signees { - // Generate key pair - priv, pub, err := ca.GenSecp256k1KeyPair() - if err != nil { - return nil, err - } - signees[i] = pub - signatures[i], err = priv.Sign(h[:]) - if err != nil { - return nil, err - } - } - req.RequestHash = *h - req.Signatures = signatures - req.Signees = signees - - return &req, nil -} - -func generateRandomBillingHeader() (tc *types.BillingHeader, err error) { - var req *types.BillingRequest - if req, err = generateRandomBillingRequest(); err != nil { - return - } - - var priv *ca.PrivateKey - if priv, _, err = ca.GenSecp256k1KeyPair(); err != nil { - return - } - - if _, _, err = req.SignRequestHeader(priv, false); err != nil { - return - } - - receivers := make([]*proto.AccountAddress, peerNum) - fees := make([]uint64, peerNum) - rewards := make([]uint64, peerNum) - for i := range fees { - h := generateRandomHash() - accountAddress := proto.AccountAddress(h) - receivers[i] = &accountAddress - fees[i] = rand.Uint64() - rewards[i] = rand.Uint64() - } - producer := proto.AccountAddress(generateRandomHash()) - - tc = types.NewBillingHeader(pi.AccountNonce(rand.Uint32()), req, producer, receivers, fees, rewards) - return tc, nil -} - -func generateRandomBillingAndBaseAccount() (*types.BaseAccount, *types.Billing, error) { - header, err := generateRandomBillingHeader() - if err != nil { - return nil, nil, err - } - priv, _, err := ca.GenSecp256k1KeyPair() - header.Producer, _ = crypto.PubKeyHash(priv.PubKey()) - - txBilling := types.NewBilling(header) - - if err := txBilling.Sign(priv); err != nil { - return nil, nil, err - } - - txBaseAccount := types.NewBaseAccount( - &types.Account{ - Address: header.Producer, - TokenBalance: [types.SupportTokenNumber]uint64{testInitBalance, testInitBalance}, - }, - ) - - if err := txBaseAccount.Sign(priv); err != nil { - return nil, nil, err - } - - return txBaseAccount, txBilling, nil -} - -func generateRandomAccountBilling() (*types.Billing, error) { - header, err := generateRandomBillingHeader() - if err != nil { - return nil, err - } - header.Producer = testAddress1 - testAddress1Nonce++ - header.Nonce = testAddress1Nonce - txBilling := types.NewBilling(header) - - if err := txBilling.Sign(testingPrivateKey); err != nil { - return nil, err - } - - return txBilling, nil -} - -func generateRandomGasAmount(n uint32) []*proto.AddrAndGas { - gasAmount := make([]*proto.AddrAndGas, n) - - for i := range gasAmount { - gasAmount[i] = &proto.AddrAndGas{ - AccountAddress: proto.AccountAddress(generateRandomHash()), - RawNodeID: proto.RawNodeID{Hash: generateRandomHash()}, - GasAmount: rand.Uint64(), - } - } - - return gasAmount -} - -func generateRandomHash() hash.Hash { - h := hash.Hash{} - rand.Read(h[:]) - return h -} - -func registerNodesWithPublicKey(pub *ca.PublicKey, diff int, num int) ( - nis []cpuminer.NonceInfo, err error) { - nis = make([]cpuminer.NonceInfo, num) - - miner := cpuminer.NewCPUMiner(nil) - nCh := make(chan cpuminer.NonceInfo) - defer close(nCh) - block := cpuminer.MiningBlock{ - Data: pub.Serialize(), - NonceChan: nCh, - Stop: nil, - } - next := cpuminer.Uint256{} - wg := &sync.WaitGroup{} - - for i := range nis { - wg.Add(1) - go func() { - defer wg.Done() - miner.ComputeBlockNonce(block, next, diff) - }() - n := <-nCh - nis[i] = n - next = n.Nonce - next.Inc() - - if err = kms.SetPublicKey(proto.NodeID(n.Hash.String()), n.Nonce, pub); err != nil { - return - } - - wg.Wait() - } - - // Register a local nonce, don't know what is the matter though - kms.SetLocalNodeIDNonce(nis[0].Hash[:], &nis[0].Nonce) - return -} - -func createRandomString(offset, length int, s *string) { - buff := make([]byte, rand.Intn(length)+offset) - rand.Read(buff) - *s = string(buff) -} - -func createTestPeersWithPrivKeys(priv *ca.PrivateKey, num int) (nis []cpuminer.NonceInfo, p *proto.Peers, err error) { - if num <= 0 { - return - } - - pub := priv.PubKey() - - nis, err = registerNodesWithPublicKey(pub, testDifficulty, num) - - if err != nil { - return - } - - s := make([]proto.NodeID, num) - h := &hash.Hash{} - - for i := range s { - rand.Read(h[:]) - s[i] = proto.NodeID(nis[i].Hash.String()) - } - - p = &proto.Peers{ - PeersHeader: proto.PeersHeader{ - Term: 0, - Leader: s[0], - Servers: s, - }, - } - - if err = p.Sign(priv); err != nil { - return - } - - return -} - -func createTestPeers(num int) (nis []cpuminer.NonceInfo, p *proto.Peers, err error) { - if num <= 0 { - return - } - - // Use a same key pair for all the servers, so that we can run multiple instances of sql-chain - // locally without breaking the LocalKeyStore - pub, err := kms.GetLocalPublicKey() - - if err != nil { - return - } - - priv, err := kms.GetLocalPrivateKey() - - if err != nil { - return - } - - nis, err = registerNodesWithPublicKey(pub, testDifficulty, num) - - if err != nil { - return - } - - s := make([]proto.NodeID, num) - h := &hash.Hash{} - - for i := range s { - rand.Read(h[:]) - s[i] = proto.NodeID(nis[i].Hash.String()) - } - - p = &proto.Peers{ - PeersHeader: proto.PeersHeader{ - Term: 0, - Leader: s[0], - Servers: s, - }, - } - - if err = p.Sign(priv); err != nil { - return - } - - return -} - func setup() { var err error - rand.Seed(time.Now().UnixNano()) rand.Read(genesisHash[:]) @@ -495,7 +71,7 @@ func setup() { // Setup logging log.SetOutput(os.Stdout) - log.SetLevel(log.FatalLevel) + log.SetLevel(log.DebugLevel) } func teardown() { diff --git a/build.sh b/build.sh deleted file mode 100755 index 848608406..000000000 --- a/build.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash -x -set -e - -param=$1 - -branch=`git rev-parse --abbrev-ref HEAD` -commitid=`git rev-parse --short HEAD` -builddate=`date +%Y%m%d%H%M%S` - -platform='' -unamestr=`uname` -if [[ "$unamestr" == 'Linux' ]]; then - platform='linux' -fi - -function getversion() { - echo $branch-$commitid-$builddate -} - -cd `dirname $0` - -version=`getversion` - -tags="${platform} sqlite_omit_load_extension" -testtags="${platform} sqlite_omit_load_extension testbinary" - -ldflags_role_bp="-X main.version=${version} -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=B ${GOLDFLAGS}" -ldflags_role_miner="-X main.version=${version} -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=M ${GOLDFLAGS}" -ldflags_role_client="-X main.version=${version} -X github.com/CovenantSQL/CovenantSQL/conf.RoleTag=C ${GOLDFLAGS}" - -test_flags="-coverpkg github.com/CovenantSQL/CovenantSQL/... -cover -race -c" - -export CGO_ENABLED=1 - -cql_utils_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-utils" -go build -ldflags "-X main.version=${version} ${GOLDFLAGS}" -o bin/cql-utils ${cql_utils_pkgpath} - - -build_bp() { - cqld_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cqld" - go build -ldflags "${ldflags_role_bp}" --tags "${tags}" -o bin/cqld ${cqld_pkgpath} - go test ${test_flags} -tags "${testtags}" -ldflags "${ldflags_role_bp}" -o bin/cqld.test ${cqld_pkgpath} -} - -build_miner() { - cql_minerd_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-minerd" - go build -ldflags "${ldflags_role_miner}" --tags "${tags}" -o bin/cql-minerd ${cql_minerd_pkgpath} - go test ${test_flags} -tags "${testtags}" -ldflags "${ldflags_role_miner}" -o bin/cql-minerd.test ${cql_minerd_pkgpath} -} - - -build_client() { - cql_observer_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-observer" - go build -ldflags "${ldflags_role_client}" -o bin/cql-observer ${cql_observer_pkgpath} - go test ${test_flags} -tags 'testbinary' -ldflags "${ldflags_role_client}" -o bin/cql-observer.test ${cql_observer_pkgpath} - - cli_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql ${cli_pkgpath} - - fuse_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-fuse" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql-fuse ${fuse_pkgpath} - - cql_adapter_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-adapter" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql-adapter ${cql_adapter_pkgpath} - - cql_faucet_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-faucet" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql-faucet ${cql_faucet_pkgpath} - - cql_mysql_adapter_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-mysql-adapter" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql-mysql-adapter ${cql_mysql_adapter_pkgpath} - - cql_explorer_pkgpath="github.com/CovenantSQL/CovenantSQL/cmd/cql-explorer" - go build -ldflags "${ldflags_role_client}" --tags "${tags}" -o bin/cql-explorer ${cql_explorer_pkgpath} -} - -case $param in - "bp") - build_bp - ;; - 'miner') - build_miner - ;; - 'client') - build_client - ;; - *) - build_bp - build_miner - build_client - ;; -esac - -echo "done" - diff --git a/client/clientbench_test.go b/client/clientbench_test.go index e41208c15..906db71f9 100644 --- a/client/clientbench_test.go +++ b/client/clientbench_test.go @@ -17,12 +17,15 @@ package client import ( + "context" "database/sql" "os" "path/filepath" "sync" "testing" + "time" + "github.com/CovenantSQL/CovenantSQL/blockproducer" "github.com/CovenantSQL/CovenantSQL/utils" "github.com/CovenantSQL/CovenantSQL/utils/log" ) @@ -30,7 +33,6 @@ import ( var ( baseDir = utils.GetProjectSrcDir() testWorkingDir = FJ(baseDir, "./test/GNTE/conf") - logDir = FJ(testWorkingDir, "./log/") once sync.Once ) @@ -53,6 +55,14 @@ func BenchmarkCovenantSQLDriver(b *testing.B) { } }) + // wait for chain service + var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel1() + err = blockproducer.WaitBPChainService(ctx1, 3*time.Second) + if err != nil { + b.Fatalf("wait for chain service failed: %v", err) + } + // create meta := ResourceMeta{} meta.Node = 3 diff --git a/client/driver.go b/client/driver.go index 7bdf10a81..0bf78092b 100644 --- a/client/driver.go +++ b/client/driver.go @@ -27,6 +27,7 @@ import ( "time" bp "github.com/CovenantSQL/CovenantSQL/blockproducer" + "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" "github.com/CovenantSQL/CovenantSQL/conf" "github.com/CovenantSQL/CovenantSQL/crypto" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" @@ -189,12 +190,13 @@ func Create(meta ResourceMeta) (dsn string, err error) { } // WaitDBCreation waits for database creation complete -func WaitDBCreation(ctx context.Context, dsn string, timeout time.Duration) (err error) { +func WaitDBCreation(ctx context.Context, dsn string) (err error) { dsnCfg, err := ParseDSN(dsn) + if err != nil { + return + } // wait for creation - var newCtx, cancel = context.WithTimeout(ctx, timeout) - defer cancel() - err = bp.WaitDatabaseCreation(newCtx, proto.DatabaseID(dsnCfg.DatabaseID), nil, 3*time.Second) + err = bp.WaitDatabaseCreation(ctx, proto.DatabaseID(dsnCfg.DatabaseID), nil, 3*time.Second) return } @@ -217,15 +219,15 @@ func Drop(dsn string) (err error) { return } -// GetStableCoinBalance get the stable coin balance of current account. -func GetStableCoinBalance() (balance uint64, err error) { +// GetTokenBalance get the token balance of current account. +func GetTokenBalance(tt types.TokenType) (balance uint64, err error) { if atomic.LoadUint32(&driverInitialized) == 0 { err = ErrNotInitialized return } - req := new(types.QueryAccountStableBalanceReq) - resp := new(types.QueryAccountStableBalanceResp) + req := new(types.QueryAccountTokenBalanceReq) + resp := new(types.QueryAccountTokenBalanceResp) var pubKey *asymmetric.PublicKey if pubKey, err = kms.GetLocalPublicKey(); err != nil { @@ -235,40 +237,136 @@ func GetStableCoinBalance() (balance uint64, err error) { if req.Addr, err = crypto.PubKeyHash(pubKey); err != nil { return } + req.TokenType = tt - if err = requestBP(route.MCCQueryAccountStableBalance, req, resp); err == nil { + if err = requestBP(route.MCCQueryAccountTokenBalance, req, resp); err == nil { + if !resp.OK { + err = ErrNoSuchTokenBalance + return + } balance = resp.Balance } return } -// GetCovenantCoinBalance get the covenant coin balance of current account. -func GetCovenantCoinBalance() (balance uint64, err error) { +// UpdatePermission sends UpdatePermission transaction to chain. +func UpdatePermission(targetUser proto.AccountAddress, + targetChain proto.AccountAddress, perm types.UserPermission) (err error) { if atomic.LoadUint32(&driverInitialized) == 0 { err = ErrNotInitialized return } - req := new(types.QueryAccountCovenantBalanceReq) - resp := new(types.QueryAccountCovenantBalanceResp) + var ( + pubKey *asymmetric.PublicKey + privKey *asymmetric.PrivateKey + addr proto.AccountAddress + nonce interfaces.AccountNonce + ) + if pubKey, err = kms.GetLocalPublicKey(); err != nil { + return + } + if privKey, err = kms.GetLocalPrivateKey(); err != nil { + return + } + if addr, err = crypto.PubKeyHash(pubKey); err != nil { + return + } - var pubKey *asymmetric.PublicKey + nonce, err = getNonce(addr) + if err != nil { + return + } + + up := types.NewUpdatePermission(&types.UpdatePermissionHeader{ + TargetSQLChain: targetChain, + TargetUser: targetUser, + Permission: perm, + Nonce: nonce, + }) + err = up.Sign(privKey) + if err != nil { + log.WithError(err).Warning("sign failed") + return + } + addTxReq := new(types.AddTxReq) + addTxResp := new(types.AddTxResp) + addTxReq.Tx = up + err = requestBP(route.MCCAddTx, addTxReq, addTxResp) + if err != nil { + log.WithError(err).Warning("send tx failed") + return + } + + return +} + +// TransferToken send Transfer transaction to chain. +func TransferToken(targetUser proto.AccountAddress, amount uint64, tokenType types.TokenType) (err error) { + if atomic.LoadUint32(&driverInitialized) == 0 { + err = ErrNotInitialized + return + } + + var ( + pubKey *asymmetric.PublicKey + privKey *asymmetric.PrivateKey + addr proto.AccountAddress + nonce interfaces.AccountNonce + ) if pubKey, err = kms.GetLocalPublicKey(); err != nil { return } + if privKey, err = kms.GetLocalPrivateKey(); err != nil { + return + } + if addr, err = crypto.PubKeyHash(pubKey); err != nil { + return + } - if req.Addr, err = crypto.PubKeyHash(pubKey); err != nil { + nonce, err = getNonce(addr) + if err != nil { return } - if err = requestBP(route.MCCQueryAccountCovenantBalance, req, resp); err == nil { - balance = resp.Balance + tran := types.NewTransfer(&types.TransferHeader{ + Sender: addr, + Receiver: targetUser, + Amount: amount, + TokenType: tokenType, + Nonce: nonce, + }) + err = tran.Sign(privKey) + if err != nil { + log.WithError(err).Warning("sign failed") + return + } + addTxReq := new(types.AddTxReq) + addTxResp := new(types.AddTxResp) + addTxReq.Tx = tran + err = requestBP(route.MCCAddTx, addTxReq, addTxResp) + if err != nil { + log.WithError(err).Warning("send tx failed") + return } return } +func getNonce(addr proto.AccountAddress) (nonce interfaces.AccountNonce, err error) { + nonceReq := new(types.NextAccountNonceReq) + nonceResp := new(types.NextAccountNonceResp) + nonceReq.Addr = addr + err = requestBP(route.MCCNextAccountNonce, nonceReq, nonceResp) + if err != nil { + log.WithError(err).Warning("get nonce failed") + return + } + nonce = nonceResp.Nonce + return +} + func requestBP(method route.RemoteFunc, request interface{}, response interface{}) (err error) { var bpNodeID proto.NodeID if bpNodeID, err = rpc.GetCurrentBP(); err != nil { diff --git a/client/driver_test.go b/client/driver_test.go index 19dbb59c4..7425d1f85 100644 --- a/client/driver_test.go +++ b/client/driver_test.go @@ -28,6 +28,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/crypto/kms" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/route" + "github.com/CovenantSQL/CovenantSQL/types" "github.com/CovenantSQL/CovenantSQL/utils/log" . "github.com/smartystreets/goconvey/convey" ) @@ -68,7 +69,9 @@ func TestCreate(t *testing.T) { dsn, err = Create(ResourceMeta{}) So(err, ShouldBeNil) - err = WaitDBCreation(context.Background(), dsn, time.Nanosecond) + waitCtx, cancelWait := context.WithTimeout(context.Background(), time.Nanosecond) + defer cancelWait() + err = WaitDBCreation(waitCtx, dsn) So(err, ShouldResemble, context.DeadlineExceeded) // Calculate database ID @@ -87,7 +90,9 @@ func TestCreate(t *testing.T) { UseLeader: true, }) - err = WaitDBCreation(context.Background(), dsn, time.Minute) + waitCtx2, cancelWait2 := context.WithTimeout(context.Background(), time.Minute) + defer cancelWait2() + err = WaitDBCreation(waitCtx2, dsn) So(err, ShouldBeNil) }) } @@ -104,8 +109,8 @@ func TestDrop(t *testing.T) { }) } -func TestGetCovenantCoinBalance(t *testing.T) { - Convey("test get covenant coin balance", t, func() { +func TestGetTokenBalance(t *testing.T) { + Convey("test get token balance", t, func() { var stopTestService func() var err error stopTestService, _, err = startTestService() @@ -113,25 +118,13 @@ func TestGetCovenantCoinBalance(t *testing.T) { defer stopTestService() var balance uint64 - balance, err = GetCovenantCoinBalance() + balance, err = GetTokenBalance(types.Particle) So(err, ShouldBeNil) So(balance, ShouldEqual, 0) - }) -} -func TestGetStableCoinBalance(t *testing.T) { - Convey("test get stable coin balance", t, func() { - var stopTestService func() - var err error - stopTestService, _, err = startTestService() - So(err, ShouldBeNil) - defer stopTestService() - - var balance uint64 - balance, err = GetStableCoinBalance() + balance, err = GetTokenBalance(-1) - So(err, ShouldBeNil) - So(balance, ShouldEqual, 0) + So(err, ShouldEqual, ErrNoSuchTokenBalance) }) } diff --git a/client/errors.go b/client/errors.go index d9b5ca49a..967e89f02 100644 --- a/client/errors.go +++ b/client/errors.go @@ -30,4 +30,6 @@ var ( ErrInvalidRequestSeq = errors.New("invalid request sequence applied") // ErrInvalidProfile indicates the SQLChain profile is invalid. ErrInvalidProfile = errors.New("invalid sqlchain profile") + // ErrNoSuchTokenBalance indicates no such token balance in chain. + ErrNoSuchTokenBalance = errors.New("no such token balance") ) diff --git a/client/helper_test.go b/client/helper_test.go index 8b2fa2dde..0db24c669 100644 --- a/client/helper_test.go +++ b/client/helper_test.go @@ -58,13 +58,9 @@ var ( // fake BPDB service type stubBPService struct{} -func (s *stubBPService) QueryAccountStableBalance(req *types.QueryAccountStableBalanceReq, - resp *types.QueryAccountStableBalanceResp) (err error) { - return -} - -func (s *stubBPService) QueryAccountCovenantBalance(req *types.QueryAccountCovenantBalanceReq, - resp *types.QueryAccountCovenantBalanceResp) (err error) { +func (s *stubBPService) QueryAccountTokenBalance(req *types.QueryAccountTokenBalanceReq, + resp *types.QueryAccountTokenBalanceResp) (err error) { + resp.OK = req.TokenType.Listed() return } diff --git a/client/result.go b/client/result.go index 5faa21deb..ad277dac4 100644 --- a/client/result.go +++ b/client/result.go @@ -21,7 +21,7 @@ type execResult struct { lastInsertID int64 } -// LastInsertId teturn last inserted ID. +// LastInsertId return last inserted ID. func (r *execResult) LastInsertId() (int64, error) { return r.lastInsertID, nil } diff --git a/cmd/cql-adapter/api/account.go b/cmd/cql-adapter/api/account.go index d06e49389..96cd68e15 100644 --- a/cmd/cql-adapter/api/account.go +++ b/cmd/cql-adapter/api/account.go @@ -20,6 +20,7 @@ import ( "net/http" "github.com/CovenantSQL/CovenantSQL/client" + "github.com/CovenantSQL/CovenantSQL/types" "github.com/CovenantSQL/CovenantSQL/utils/log" ) @@ -39,7 +40,7 @@ func (a *accountAPI) StableCoinBalance(rw http.ResponseWriter, r *http.Request) var balance uint64 var err error - if balance, err = client.GetStableCoinBalance(); err != nil { + if balance, err = client.GetTokenBalance(types.Particle); err != nil { sendResponse(http.StatusInternalServerError, false, err, nil, rw) } else { sendResponse(http.StatusOK, true, nil, map[string]interface{}{ @@ -57,7 +58,7 @@ func (a *accountAPI) CovenantCoinBalance(rw http.ResponseWriter, r *http.Request var balance uint64 var err error - if balance, err = client.GetCovenantCoinBalance(); err != nil { + if balance, err = client.GetTokenBalance(types.Wave); err != nil { sendResponse(http.StatusInternalServerError, false, err, nil, rw) } else { sendResponse(http.StatusOK, true, nil, map[string]interface{}{ diff --git a/cmd/cql-adapter/config/errors.go b/cmd/cql-adapter/config/errors.go index 1314f0d64..312887eda 100644 --- a/cmd/cql-adapter/config/errors.go +++ b/cmd/cql-adapter/config/errors.go @@ -21,8 +21,6 @@ import "github.com/pkg/errors" var ( // ErrEmptyAdapterConfig defines empty adapter config. ErrEmptyAdapterConfig = errors.New("empty adapter config") - // ErrRequireServerCertificate defines error of empty server certificate. - ErrRequireServerCertificate = errors.New("require server certificate") // ErrInvalidStorageConfig defines error on incomplete storage config. ErrInvalidStorageConfig = errors.New("invalid storage config") // ErrInvalidCertificateFile defines invalid certificate file error. diff --git a/cmd/cql-adapter/server.go b/cmd/cql-adapter/server.go index 3c880b69f..a9b739eb1 100644 --- a/cmd/cql-adapter/server.go +++ b/cmd/cql-adapter/server.go @@ -29,8 +29,7 @@ import ( // HTTPAdapter is a adapter for covenantsql/alternative sqlite3 service. type HTTPAdapter struct { - tlsConfig *tls.Config - server *http.Server + server *http.Server } // NewHTTPAdapter creates adapter to service. diff --git a/cmd/cql-adapter/storage/sqlite3.go b/cmd/cql-adapter/storage/sqlite3.go index eb794d511..9eeaab39f 100644 --- a/cmd/cql-adapter/storage/sqlite3.go +++ b/cmd/cql-adapter/storage/sqlite3.go @@ -24,6 +24,7 @@ import ( "math/rand" "os" "path/filepath" + // Import sqlite3 manually. _ "github.com/CovenantSQL/go-sqlite3-encrypt" ) diff --git a/cmd/cql-faucet/api.go b/cmd/cql-faucet/api.go index 631a54598..0858828ff 100644 --- a/cmd/cql-faucet/api.go +++ b/cmd/cql-faucet/api.go @@ -35,7 +35,7 @@ const ( var ( apiTimeout = time.Second * 10 - regexAddress = regexp.MustCompile("^4[a-zA-Z0-9]{50}$") + regexAddress = regexp.MustCompile("^[a-zA-Z0-9]{64}$") regexMediaURL = regexp.MustCompile("^(http|ftp|https)://([\\w\\-_]+(?:(?:\\.[\\w\\-_]+)+))([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?$") regexApplicationID = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$") ) diff --git a/cmd/cql-faucet/persistence.go b/cmd/cql-faucet/persistence.go index dfdc3d458..140a6c6d6 100644 --- a/cmd/cql-faucet/persistence.go +++ b/cmd/cql-faucet/persistence.go @@ -26,6 +26,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/conf" "github.com/CovenantSQL/CovenantSQL/utils/log" uuid "github.com/satori/go.uuid" + // Load sqlite3 database driver. _ "github.com/CovenantSQL/go-sqlite3-encrypt" ) diff --git a/cmd/cql-faucet/verifier.go b/cmd/cql-faucet/verifier.go index f12502693..2a7961d49 100644 --- a/cmd/cql-faucet/verifier.go +++ b/cmd/cql-faucet/verifier.go @@ -210,12 +210,13 @@ func (v *Verifier) dispense() (err error) { } func (v *Verifier) dispenseOne(r *applicationRecord) (err error) { - balanceReq := &pt.QueryAccountStableBalanceReq{} - balanceRes := &pt.QueryAccountStableBalanceResp{} + balanceReq := &pt.QueryAccountTokenBalanceReq{} + balanceRes := &pt.QueryAccountTokenBalanceResp{} balanceReq.Addr = v.vaultAddress + balanceReq.TokenType = pt.Particle // get current balance - if err = requestBP(route.MCCQueryAccountStableBalance.String(), balanceReq, balanceRes); err != nil { + if err = requestBP(route.MCCQueryAccountTokenBalance.String(), balanceReq, balanceRes); err != nil { log.WithError(err).Warning("get account balance failed") } else { log.WithField("balance", balanceRes.Balance).Info("get account balance") @@ -234,28 +235,6 @@ func (v *Verifier) dispenseOne(r *applicationRecord) (err error) { // decode target account address var targetAddress proto.AccountAddress - var addrVersion byte - if addrVersion, targetAddress, err = crypto.Addr2Hash(r.address); err != nil || addrVersion != crypto.TestNet { - if err == nil && addrVersion != crypto.TestNet { - err = ErrInvalidAddress - } - - // log error - log.WithError(err).Warning("decode transfer target address failed") - - // mark failed - r.failReason = err.Error() - r.state = StateFailed - if err = v.p.updateRecord(r); err != nil { - return - } - - log.WithFields(log.Fields(r.asMap())).Info("dispensed application record failed") - - // skip invalid address faucet application - err = nil - return - } req := &pt.AddTxReq{} resp := &pt.AddTxResp{} diff --git a/cmd/cql-fuse/block_test.go b/cmd/cql-fuse/block_test.go index b36115b50..6fed70bc2 100644 --- a/cmd/cql-fuse/block_test.go +++ b/cmd/cql-fuse/block_test.go @@ -245,6 +245,15 @@ func initTestDB() (*sql.DB, func()) { return nil, stopNodes } + // wait for chain service + var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel1() + err = bp.WaitBPChainService(ctx1, 3*time.Second) + if err != nil { + log.Errorf("wait for chain service failed: %v", err) + return nil, stopNodes + } + // create meta := client.ResourceMeta{} meta.Node = 1 @@ -266,9 +275,9 @@ func initTestDB() (*sql.DB, func()) { } // wait for creation - var ctx, cancel = context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - err = bp.WaitDatabaseCreation(ctx, proto.DatabaseID(dsnCfg.DatabaseID), db, 3*time.Second) + var ctx2, cancel2 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel2() + err = bp.WaitDatabaseCreation(ctx2, proto.DatabaseID(dsnCfg.DatabaseID), db, 3*time.Second) if err != nil { log.Errorf("wait for creation failed: %v", err) return nil, stopNodes diff --git a/cmd/cql-minerd/bench.sh b/cmd/cql-minerd/bench.sh index 5e383a511..c36b31bb6 100755 --- a/cmd/cql-minerd/bench.sh +++ b/cmd/cql-minerd/bench.sh @@ -1,6 +1,7 @@ #!/bin/bash -../../build.sh && \ +make -C ../../ clean && \ +make -C ../../ use_all_cores && \ go test -bench=^BenchmarkSQLite$ -benchtime=10s -run ^$ && \ go test -bench=^BenchmarkMinerOne$ -benchtime=10s -run ^$ && \ go test -bench=^BenchmarkMinerOneNoSign$ -benchtime=10s -run ^$ && \ diff --git a/cmd/cql-minerd/benchGNTE.sh b/cmd/cql-minerd/benchGNTE.sh index 03bd8e2b5..89181bd47 100755 --- a/cmd/cql-minerd/benchGNTE.sh +++ b/cmd/cql-minerd/benchGNTE.sh @@ -1,6 +1,7 @@ #!/bin/bash -#../../build.sh && \ +#make -C ../../ clean && \ +#make -C ../../ use_all_cores && \ go test -bench=^BenchmarkMinerGNTE1$ -benchtime=10s -run ^$ |tee gnte.log go test -bench=^BenchmarkMinerGNTE2$ -benchtime=10s -run ^$ |tee -a gnte.log go test -bench=^BenchmarkMinerGNTE3$ -benchtime=10s -run ^$ |tee -a gnte.log diff --git a/cmd/cql-minerd/integration_test.go b/cmd/cql-minerd/integration_test.go index fdec6fe8c..04e897266 100644 --- a/cmd/cql-minerd/integration_test.go +++ b/cmd/cql-minerd/integration_test.go @@ -35,7 +35,6 @@ import ( "time" bp "github.com/CovenantSQL/CovenantSQL/blockproducer" - "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" "github.com/CovenantSQL/CovenantSQL/client" "github.com/CovenantSQL/CovenantSQL/conf" "github.com/CovenantSQL/CovenantSQL/crypto" @@ -52,12 +51,11 @@ import ( ) var ( - baseDir = utils.GetProjectSrcDir() - testWorkingDir = FJ(baseDir, "./test/") - logDir = FJ(testWorkingDir, "./log/") - testGasPrice uint64 = 1 - testInitTokenAmount uint64 = 1000000000 - testAdvancePayment uint64 = 20000000 + baseDir = utils.GetProjectSrcDir() + testWorkingDir = FJ(baseDir, "./test/") + logDir = FJ(testWorkingDir, "./log/") + testGasPrice uint64 = 1 + testAdvancePayment uint64 = 20000000 ) var nodeCmds []*utils.CMD @@ -378,6 +376,13 @@ func TestFullProcess(t *testing.T) { GasPrice: testGasPrice, AdvancePayment: testAdvancePayment, } + // wait for chain service + var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel1() + err = bp.WaitBPChainService(ctx1, 3*time.Second) + if err != nil { + t.Fatalf("wait for chain service failed: %v", err) + } dsn, err := client.Create(meta) So(err, ShouldBeNil) @@ -545,11 +550,21 @@ func TestFullProcess(t *testing.T) { So(err, ShouldBeNil) for _, user := range profileResp.Profile.Users { log.Infof("user (%s) left advance payment: %d", user.Address.String(), user.AdvancePayment) + if user.AdvancePayment == testAdvancePayment { + time.Sleep(20 * time.Second) + break + } + } + err = rpc.RequestBP(route.MCCQuerySQLChainProfile.String(), profileReq, profileResp) + So(err, ShouldBeNil) + for _, user := range profileResp.Profile.Users { So(user.AdvancePayment, ShouldNotEqual, testAdvancePayment) } + getIncome := false for _, miner := range profileResp.Profile.Miners { - So(miner.PendingIncome != 0 || miner.ReceivedIncome != 0, ShouldBeTrue) + getIncome = getIncome || (miner.PendingIncome != 0 || miner.ReceivedIncome != 0) } + So(getIncome, ShouldBeTrue) err = db.Close() So(err, ShouldBeNil) @@ -708,6 +723,14 @@ func benchMiner(b *testing.B, minerCount uint16, bypassSign bool) { // create meta := client.ResourceMeta{} meta.Node = minerCount + // wait for chain service + var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel1() + err = bp.WaitBPChainService(ctx1, 3*time.Second) + if err != nil { + b.Fatalf("wait for chain service failed: %v", err) + } + dsn, err = client.Create(meta) So(err, ShouldBeNil) log.Infof("the created database dsn is %v", dsn) @@ -796,6 +819,15 @@ func benchGNTEMiner(b *testing.B, minerCount uint16, bypassSign bool) { // create meta := client.ResourceMeta{} meta.Node = minerCount + meta.AdvancePayment = 1000000000 + // wait for chain service + var ctx1, cancel1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel1() + err = bp.WaitBPChainService(ctx1, 3*time.Second) + if err != nil { + b.Fatalf("wait for chain service failed: %v", err) + } + dsn, err = client.Create(meta) So(err, ShouldBeNil) log.Infof("the created database dsn is %v", dsn) @@ -898,19 +930,3 @@ func BenchmarkMinerGNTE8(b *testing.B) { benchGNTEMiner(b, 8, false) }) } - -func getNonce(addr proto.AccountAddress) (nonce interfaces.AccountNonce, err error) { - // allocate nonce - nonceReq := &types.NextAccountNonceReq{} - nonceResp := &types.NextAccountNonceResp{} - nonceReq.Addr = addr - - if err = rpc.RequestBP(route.MCCNextAccountNonce.String(), nonceReq, nonceResp); err != nil { - // allocate nonce failed - log.WithError(err).Warning("allocate nonce for transaction failed") - return - } - - nonce = nonceResp.Nonce - return -} diff --git a/cmd/cql-minerd/main.go b/cmd/cql-minerd/main.go index 44e42c4e3..e922164e0 100644 --- a/cmd/cql-minerd/main.go +++ b/cmd/cql-minerd/main.go @@ -28,6 +28,7 @@ import ( "runtime" "github.com/CovenantSQL/CovenantSQL/metric" + //"runtime/trace" "syscall" "time" @@ -139,7 +140,7 @@ func main() { if conf.GConf.Miner == nil { log.Fatal("miner config does not exists") } - if conf.GConf.Miner.MetricCollectInterval.Seconds() <= 0 { + if conf.GConf.Miner.ProvideServiceInterval.Seconds() <= 0 { log.Fatal("miner metric collect interval is invalid") } if conf.GConf.Miner.MaxReqTimeGap.Seconds() <= 0 { @@ -188,7 +189,7 @@ func main() { // start prometheus collector reg := metric.StartMetricCollector() - tick := time.NewTicker(conf.GConf.Miner.MetricCollectInterval) + tick := time.NewTicker(conf.GConf.Miner.ProvideServiceInterval) defer tick.Stop() for { diff --git a/cmd/cql-minerd/mcprof.sh b/cmd/cql-minerd/mcprof.sh index 4c002b7d8..d66b53308 100755 --- a/cmd/cql-minerd/mcprof.sh +++ b/cmd/cql-minerd/mcprof.sh @@ -1,7 +1,8 @@ #!/bin/sh -x ../../cleanupDB.sh -../../build.sh +make -C ../../ clean +make -C ../../ use_all_cores (go test -bench=^BenchmarkMinerTwo$ -benchtime=40s -run ^$ &) && \ (sleep 25 && DSN=`cat .dsn` go test '-bench=^BenchmarkClientOnly$' -benchtime=20s -run '^$') diff --git a/cmd/cql-minerd/pprof.sh b/cmd/cql-minerd/pprof.sh index f59633a46..4eb3555b5 100755 --- a/cmd/cql-minerd/pprof.sh +++ b/cmd/cql-minerd/pprof.sh @@ -1,7 +1,8 @@ #!/bin/sh -x ../../cleanupDB.sh -../../build.sh +make -C ../../ clean +make -C ../../ use_all_cores go test -bench=^BenchmarkMinerTwo$ -benchtime=15s -run ^$ go tool pprof -text miner1.profile > pprof.txt diff --git a/cmd/cql-observer/observation_test.go b/cmd/cql-observer/observation_test.go index 54c6e1e2d..039f9bf28 100644 --- a/cmd/cql-observer/observation_test.go +++ b/cmd/cql-observer/observation_test.go @@ -252,20 +252,18 @@ func TestFullProcess(t *testing.T) { Convey("test full process", t, func() { var ( - err error - cliPriv *asymmetric.PrivateKey - addr, addr2 proto.AccountAddress - dsn, dsn2 string - cfg, cfg2 *client.Config - dbID, dbID2 string - ctx, ctx2 context.Context - ccl, ccl2 context.CancelFunc + err error + cliPriv *asymmetric.PrivateKey + addr, addr2 proto.AccountAddress + dsn, dsn2 string + cfg, cfg2 *client.Config + dbID, dbID2 string + ctx1, ctx2, ctx3 context.Context + ccl1, ccl2, ccl3 context.CancelFunc ) startNodes() defer stopNodes() - time.Sleep(10 * time.Second) - err = client.Init(FJ(testWorkingDir, "./observation/node_c/config.yaml"), []byte("")) So(err, ShouldBeNil) @@ -280,6 +278,12 @@ func TestFullProcess(t *testing.T) { FJ(testWorkingDir, "./observation/node_miner_1/private.key"), []byte{}) So(err, ShouldBeNil) + // wait until bp chain service is ready + ctx1, ccl1 = context.WithTimeout(context.Background(), 1*time.Minute) + defer ccl1() + err = bp.WaitBPChainService(ctx1, 3*time.Second) + So(err, ShouldBeNil) + // create _, dsn, err = bp.Create(types.ResourceMeta{ TargetMiners: []proto.AccountAddress{addr}, @@ -295,9 +299,9 @@ func TestFullProcess(t *testing.T) { cfg, err = client.ParseDSN(dsn) So(err, ShouldBeNil) dbID = cfg.DatabaseID - ctx, ccl = context.WithTimeout(context.Background(), 5*time.Minute) - defer ccl() - err = bp.WaitDatabaseCreation(ctx, proto.DatabaseID(dbID), db, 3*time.Second) + ctx2, ccl2 = context.WithTimeout(context.Background(), 5*time.Minute) + defer ccl2() + err = bp.WaitDatabaseCreation(ctx2, proto.DatabaseID(dbID), db, 3*time.Second) So(err, ShouldBeNil) _, err = db.Exec("CREATE TABLE test (test int)") @@ -367,9 +371,9 @@ func TestFullProcess(t *testing.T) { So(err, ShouldBeNil) dbID2 = cfg2.DatabaseID So(dbID, ShouldNotResemble, dbID2) - ctx2, ccl2 = context.WithTimeout(context.Background(), 5*time.Minute) - defer ccl2() - err = bp.WaitDatabaseCreation(ctx2, proto.DatabaseID(dbID2), db2, 3*time.Second) + ctx3, ccl3 = context.WithTimeout(context.Background(), 5*time.Minute) + defer ccl3() + err = bp.WaitDatabaseCreation(ctx3, proto.DatabaseID(dbID2), db2, 3*time.Second) So(err, ShouldBeNil) _, err = db2.Exec("CREATE TABLE test (test int)") @@ -412,7 +416,7 @@ func TestFullProcess(t *testing.T) { }() // wait for the observer to collect blocks, two periods is enough - time.Sleep(conf.GConf.SQLChainPeriod * 2) + time.Sleep(conf.GConf.SQLChainPeriod * 5) // test get genesis block by height res, err := getJSON("v1/height/%v/0", dbID) @@ -421,14 +425,20 @@ func TestFullProcess(t *testing.T) { So(ensureSuccess(res.Int("block", "height")), ShouldEqual, 0) genesisHash := ensureSuccess(res.String("block", "hash")).(string) + res, err = getJSON("v1/head/%v", dbID) + So(err, ShouldBeNil) + So(ensureSuccess(res.Interface("block")), ShouldNotBeNil) + maxHeight := ensureSuccess(res.Int("block", "height")).(int) + So(maxHeight, ShouldBeGreaterThan, 0) + // test get first containable block var ( blockHash string byHeightBlockResult interface{} ) - // access 5 blocks - for i := 1; i <= 5; i++ { + // access from max height to found a non-empty block + for i := maxHeight; i > 0; i-- { res, err = getJSON("v3/height/%v/%d", dbID, i) So(err, ShouldBeNil) So(ensureSuccess(res.Interface("block")), ShouldNotBeNil) diff --git a/cmd/cql-utils/addrgen.go b/cmd/cql-utils/addrgen.go index b639f5a63..3c9a9bd77 100644 --- a/cmd/cql-utils/addrgen.go +++ b/cmd/cql-utils/addrgen.go @@ -18,7 +18,6 @@ package main import ( "encoding/hex" - "flag" "fmt" "os" @@ -28,14 +27,6 @@ import ( "github.com/CovenantSQL/CovenantSQL/utils/log" ) -var ( - isTestNetAddr bool -) - -func init() { - flag.BoolVar(&isTestNetAddr, "addrgen", false, "addrgen generates a testnet address from your key pair") -} - func runAddrgen() { var publicKey *asymmetric.PublicKey @@ -68,10 +59,6 @@ func runAddrgen() { if err != nil { log.WithError(err).Fatal("unexpected error") } - addr, err := crypto.PubKey2Addr(publicKey, crypto.TestNet) - if err != nil { - log.WithError(err).Fatal("unexpected error") - } - fmt.Printf("wallet address hash: %s\n", keyHash.String()) - fmt.Printf("wallet address: %s\n", addr) + + fmt.Printf("wallet address: %s\n", keyHash.String()) } diff --git a/cmd/cql-utils/confgen.go b/cmd/cql-utils/confgen.go index 1033eba5f..cc7aa8ee6 100644 --- a/cmd/cql-utils/confgen.go +++ b/cmd/cql-utils/confgen.go @@ -51,7 +51,8 @@ func runConfgen() { if _, err := os.Stat(workingRoot); err == nil { reader := bufio.NewReader(os.Stdin) - fmt.Println("The directory has already existed. \nDo you want to delete it? (y or n, press Enter for default n):") + fmt.Printf("The directory \"%s\" already exists. \nDo you want to delete it? (y or n, press Enter for default n):\n", + workingRoot) t, err := reader.ReadString('\n') t = strings.Trim(t, "\n") if err != nil { diff --git a/cmd/cql-utils/keygen.go b/cmd/cql-utils/keygen.go index 816477bde..e1541541f 100644 --- a/cmd/cql-utils/keygen.go +++ b/cmd/cql-utils/keygen.go @@ -31,7 +31,8 @@ import ( func runKeygen() *asymmetric.PublicKey { if _, err := os.Stat(privateKeyFile); err == nil { reader := bufio.NewReader(os.Stdin) - fmt.Println("Private key file has already existed. \nDo you want to delete it? (y or n, press Enter for default n):") + fmt.Printf("Private key file \"%s\" already exists. \nDo you want to delete it? (y or n, press Enter for default n):\n", + privateKeyFile) t, err := reader.ReadString('\n') t = strings.Trim(t, "\n") if err != nil { diff --git a/cmd/cql/main.go b/cmd/cql/main.go index ff9232e47..1c0efd6a6 100644 --- a/cmd/cql/main.go +++ b/cmd/cql/main.go @@ -18,6 +18,7 @@ package main import ( + "context" "database/sql" "encoding/json" "flag" @@ -25,12 +26,15 @@ import ( "io" "os" "os/user" + "regexp" "runtime" "strconv" "strings" "github.com/CovenantSQL/CovenantSQL/client" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" + "github.com/CovenantSQL/CovenantSQL/proto" + "github.com/CovenantSQL/CovenantSQL/types" "github.com/CovenantSQL/CovenantSQL/utils/log" sqlite3 "github.com/CovenantSQL/go-sqlite3-encrypt" "github.com/xo/dburl" @@ -57,11 +61,25 @@ var ( variables varsFlag // DML variables - createDB string // as a instance meta json string or simply a node count - dropDB string // database id to drop - getBalance bool // get balance of current account + createDB string // as a instance meta json string or simply a node count + dropDB string // database id to drop + updatePermission string // update user's permission on specific sqlchain + transferToken string // transfer token to target account + getBalance bool // get balance of current account + getBalanceWithTokenName string // get specific token's balance of current account ) +type userPermission struct { + TargetChain proto.AccountAddress `json:"chain"` + TargetUser proto.AccountAddress `json:"user"` + Perm string `json:"perm"` +} + +type tranToken struct { + TargetUser proto.AccountAddress `json:"addr"` + Amount string `json:"amount"` +} + type varsFlag struct { flag.Value vars []string @@ -148,8 +166,14 @@ func init() { RowsAffected: func(sql.Result) (int64, error) { return 0, nil }, - Open: func(url *dburl.URL) (func(string, string) (*sql.DB, error), error) { + Open: func(url *dburl.URL) (handler func(driver string, dsn string) (*sql.DB, error), err error) { log.Infof("connecting to %#v", url.DSN) + + // wait for database to become ready + if err = client.WaitDBCreation(context.Background(), dsn); err != nil { + return + } + return sql.Open, nil }, }) @@ -188,7 +212,10 @@ func init() { // DML flags flag.StringVar(&createDB, "create", "", "create database, argument can be instance requirement json or simply a node count requirement") flag.StringVar(&dropDB, "drop", "", "drop database, argument should be a database id (without covenantsql:// scheme is acceptable)") + flag.StringVar(&updatePermission, "update-perm", "", "update user's permission on specific sqlchain") + flag.StringVar(&transferToken, "transfer", "", "transfer token to target account") flag.BoolVar(&getBalance, "get-balance", false, "get balance of current account") + flag.StringVar(&getBalanceWithTokenName, "token-balance", "", "get specific token's balance of current account, e.g. Particle, Wave, and etc.") } func main() { @@ -211,21 +238,43 @@ func main() { if getBalance { var stableCoinBalance, covenantCoinBalance uint64 - if stableCoinBalance, err = client.GetStableCoinBalance(); err != nil { - log.WithError(err).Error("get stable coin balance failed") + if stableCoinBalance, err = client.GetTokenBalance(types.Particle); err != nil { + log.WithError(err).Error("get Particle balance failed") return } - if covenantCoinBalance, err = client.GetCovenantCoinBalance(); err != nil { - log.WithError(err).Error("get covenant coin balance failed") + if covenantCoinBalance, err = client.GetTokenBalance(types.Wave); err != nil { + log.WithError(err).Error("get Wave balance failed") return } - log.Infof("stable coin balance is: %d", stableCoinBalance) - log.Infof("covenant coin balance is: %d", covenantCoinBalance) + log.Infof("Particle balance is: %d", stableCoinBalance) + log.Infof("Wave balance is: %d", covenantCoinBalance) return } + if getBalanceWithTokenName != "" { + var tokenBalance uint64 + tokenType := types.FromString(getBalanceWithTokenName) + if !tokenType.Listed() { + values := make([]string, len(types.TokenList)) + for i := types.Particle; i < types.SupportTokenNumber; i++ { + values[i] = types.TokenList[i] + } + log.Errorf("no such token supporting in CovenantSQL (what we support: %s)", + strings.Join(values, ", ")) + os.Exit(-1) + return + } + if tokenBalance, err = client.GetTokenBalance(tokenType); err != nil { + log.WithError(err).Error("get token balance failed") + os.Exit(-1) + return + } + log.Infof("%s balance is: %d", tokenType.String(), tokenBalance) + return + } + if dropDB != "" { // drop database if _, err := client.ParseDSN(dropDB); err != nil { @@ -276,6 +325,83 @@ func main() { return } + if updatePermission != "" { + // update user's permission on sqlchain + var perm userPermission + if err := json.Unmarshal([]byte(updatePermission), &perm); err != nil { + log.WithError(err).Errorf("update permission failed: invalid permission description") + os.Exit(-1) + return + } + + var p types.UserPermission + p.FromString(perm.Perm) + if p > types.NumberOfUserPermission { + log.WithError(err).Errorf("update permission failed: invalid permission description") + os.Exit(-1) + return + } + + err := client.UpdatePermission(perm.TargetUser, perm.TargetChain, p) + + if err != nil { + log.WithError(err).Error("update permission failed") + os.Exit(-1) + return + } + + log.Info("succeed in sending transaction to CovenantSQL") + return + } + + if transferToken != "" { + // transfer token + var tran tranToken + if err := json.Unmarshal([]byte(transferToken), &tran); err != nil { + log.WithError(err).Errorf("transfer token failed: invalid transfer description") + os.Exit(-1) + return + } + + var validAmount = regexp.MustCompile(`^([0-9]+) *([a-zA-Z]+)$`) + if !validAmount.MatchString(tran.Amount) { + log.Error("transfer token failed: invalid transfer description") + os.Exit(-1) + return + } + amountUnit := validAmount.FindStringSubmatch(tran.Amount) + if len(amountUnit) != 3 { + log.Error("transfer token failed: invalid transfer description") + for _, v := range amountUnit { + log.Error(v) + } + os.Exit(-1) + return + } + amount, err := strconv.ParseUint(amountUnit[1], 10, 64) + if err != nil { + log.Error("transfer token failed: invalid token amount") + os.Exit(-1) + return + } + unit := types.FromString(amountUnit[2]) + if !unit.Listed() { + log.Error("transfer token failed: invalid token type") + os.Exit(-1) + return + } + + err = client.TransferToken(tran.TargetUser, amount, unit) + if err != nil { + log.WithError(err).Error("transfer token failed") + os.Exit(-1) + return + } + + log.Info("succeed in sending transaction to CovenantSQL") + return + } + var ( curUser *user.User available = drivers.Available() diff --git a/cmd/cqld/bench_test.go b/cmd/cqld/bench_test.go index 086d92a4e..37771d128 100644 --- a/cmd/cqld/bench_test.go +++ b/cmd/cqld/bench_test.go @@ -21,6 +21,7 @@ package main import ( "context" "net" + "os" "os/exec" "path/filepath" "sync" @@ -60,6 +61,9 @@ func start3BPs() { // start 3bps var cmd *utils.CMD + os.Remove(FJ(testWorkingDir, "./node_0/chain.db")) + os.Remove(FJ(testWorkingDir, "./node_0/dht.db")) + os.Remove(FJ(testWorkingDir, "./node_0/public.keystore")) if cmd, err = utils.RunCommandNB( FJ(baseDir, "./bin/cqld.test"), []string{"-config", FJ(testWorkingDir, "./node_0/config.yaml"), @@ -71,6 +75,9 @@ func start3BPs() { } else { log.Errorf("start node failed: %v", err) } + os.Remove(FJ(testWorkingDir, "./node_1/chain.db")) + os.Remove(FJ(testWorkingDir, "./node_1/dht.db")) + os.Remove(FJ(testWorkingDir, "./node_1/public.keystore")) if cmd, err = utils.RunCommandNB( FJ(baseDir, "./bin/cqld.test"), []string{"-config", FJ(testWorkingDir, "./node_1/config.yaml"), @@ -82,6 +89,9 @@ func start3BPs() { } else { log.Errorf("start node failed: %v", err) } + os.Remove(FJ(testWorkingDir, "./node_2/chain.db")) + os.Remove(FJ(testWorkingDir, "./node_2/dht.db")) + os.Remove(FJ(testWorkingDir, "./node_2/public.keystore")) if cmd, err = utils.RunCommandNB( FJ(baseDir, "./bin/cqld.test"), []string{"-config", FJ(testWorkingDir, "./node_2/config.yaml"), @@ -93,6 +103,8 @@ func start3BPs() { } else { log.Errorf("start node failed: %v", err) } + os.Remove(FJ(testWorkingDir, "./node_c/dht.db")) + os.Remove(FJ(testWorkingDir, "./node_c/public.keystore")) } func stopNodes() { @@ -111,8 +123,8 @@ func stopNodes() { } }(nodeCmd) } - wg.Wait() + nodeCmds = nil } func TestStartBP_CallRPC(t *testing.T) { diff --git a/cmd/cqld/bootstrap.go b/cmd/cqld/bootstrap.go index 8a6157827..4a5770f1c 100644 --- a/cmd/cqld/bootstrap.go +++ b/cmd/cqld/bootstrap.go @@ -85,6 +85,15 @@ func runNode(nodeID proto.NodeID, listenAddr string) (err error) { return } + // start server + go func() { + server.Serve() + }() + defer func() { + server.Listener.Close() + server.Stop() + }() + // init storage log.Info("init storage") var st *LocalStorage @@ -146,15 +155,6 @@ func runNode(nodeID proto.NodeID, listenAddr string) (err error) { log.Info(conf.StartSucceedMessage) //go periodicPingBlockProducer() - // start server - go func() { - server.Serve() - }() - defer func() { - server.Listener.Close() - server.Stop() - }() - signalCh := make(chan os.Signal, 1) signal.Notify( signalCh, diff --git a/cmd/cqld/cqld_test.go b/cmd/cqld/cqld_test.go new file mode 100644 index 000000000..7d3c267b6 --- /dev/null +++ b/cmd/cqld/cqld_test.go @@ -0,0 +1,90 @@ +// +build !testbinary + +/* + * Copyright 2018 The CovenantSQL Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "context" + "syscall" + "testing" + "time" + + bp "github.com/CovenantSQL/CovenantSQL/blockproducer" + "github.com/CovenantSQL/CovenantSQL/conf" + "github.com/CovenantSQL/CovenantSQL/crypto/kms" + "github.com/CovenantSQL/CovenantSQL/route" + "github.com/CovenantSQL/CovenantSQL/rpc" + "github.com/CovenantSQL/CovenantSQL/types" + "github.com/CovenantSQL/CovenantSQL/utils" + . "github.com/smartystreets/goconvey/convey" +) + +func TestCQLD(t *testing.T) { + Convey("Test cqld 3BPs", t, func() { + var ( + ctx1, ctx2 context.Context + ccl1, ccl2 context.CancelFunc + err error + ) + start3BPs() + defer stopNodes() + So(len(nodeCmds), ShouldEqual, 3) + + ctx1, ccl1 = context.WithTimeout(context.Background(), 30*time.Second) + defer ccl1() + + err = utils.WaitToConnect(ctx1, "127.0.0.1", []int{2122, 2121, 2120}, 10*time.Second) + So(err, ShouldBeNil) + + // Initialize local client + conf.GConf, err = conf.LoadConfig(FJ(testWorkingDir, "./node_c/config.yaml")) + So(err, ShouldBeNil) + route.InitKMS(conf.GConf.PubKeyStoreFile) + err = kms.InitLocalKeyPair(conf.GConf.PrivateKeyFile, []byte{}) + So(err, ShouldBeNil) + + // Wait BP chain service to be ready + ctx2, ccl2 = context.WithTimeout(context.Background(), 30*time.Second) + defer ccl2() + err = bp.WaitBPChainService(ctx2, 3*time.Second) + So(err, ShouldBeNil) + + // Wait for block producing + time.Sleep(15 * time.Second) + + // Kill one BP + err = nodeCmds[2].Cmd.Process.Signal(syscall.SIGTERM) + So(err, ShouldBeNil) + time.Sleep(15 * time.Second) + + // The other peers should be waiting + var ( + req = &types.FetchLastIrreversibleBlockReq{} + resp = &types.FetchLastIrreversibleBlockResp{} + + lastBlockCount uint32 + ) + err = rpc.RequestBP(route.MCCFetchLastIrreversibleBlock.String(), req, resp) + So(err, ShouldBeNil) + lastBlockCount = resp.Count + time.Sleep(15 * time.Second) + err = rpc.RequestBP(route.MCCFetchLastIrreversibleBlock.String(), req, resp) + So(err, ShouldBeNil) + So(resp.Count, ShouldEqual, lastBlockCount) + }) +} diff --git a/cmd/cqld/main.go b/cmd/cqld/main.go index e0f3065f7..5164735d7 100644 --- a/cmd/cqld/main.go +++ b/cmd/cqld/main.go @@ -55,7 +55,6 @@ var ( noLogo bool showVersion bool configFile string - genKeyPair bool clientMode bool clientOperation string diff --git a/conf/config.go b/conf/config.go index e268d8b6b..e2949a1c8 100644 --- a/conf/config.go +++ b/conf/config.go @@ -97,9 +97,9 @@ type MinerDatabaseFixture struct { // MinerInfo for miner config. type MinerInfo struct { // node basic config. - RootDir string `yaml:"RootDir"` - MaxReqTimeGap time.Duration `yaml:"MaxReqTimeGap,omitempty"` - MetricCollectInterval time.Duration `yaml:"MetricCollectInterval,omitempty"` + RootDir string `yaml:"RootDir"` + MaxReqTimeGap time.Duration `yaml:"MaxReqTimeGap,omitempty"` + ProvideServiceInterval time.Duration `yaml:"ProvideServiceInterval,omitempty"` // when test mode, fixture database config is used. IsTestMode bool `yaml:"IsTestMode,omitempty"` @@ -139,7 +139,8 @@ type Config struct { SeedBPNodes []proto.Node `yaml:"-"` QPS uint32 `yaml:"QPS"` - BillingPeriod uint32 `yaml:"BillingPeriod"` // BillingPeriod is for sql chain miners syncing billing with main chain + ChainBusPeriod time.Duration `yaml:"ChainBusPeriod"` + BillingBlockCount uint64 `yaml:"BillingBlockCount"` // BillingBlockCount is for sql chain miners syncing billing with main chain BPPeriod time.Duration `yaml:"BPPeriod"` BPTick time.Duration `yaml:"BPTick"` SQLChainPeriod time.Duration `yaml:"SQLChainPeriod"` diff --git a/conf/testnet/config.yaml b/conf/testnet/config.yaml index 94b2ab825..2b4df6adf 100644 --- a/conf/testnet/config.yaml +++ b/conf/testnet/config.yaml @@ -19,40 +19,67 @@ DNSSeed: - 202.46.34.76 BlockProducer: - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" - NodeID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + NodeID: 00000000000589366268c274fdc11ec8bdb17e668d2f619555a2e9c1a29c91d8 Nonce: - a: 313283 + a: 14396347928 b: 0 c: 0 - d: 0 + d: 6148914694092305796 KnownNodes: -- ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 +- ID: 00000000000589366268c274fdc11ec8bdb17e668d2f619555a2e9c1a29c91d8 Nonce: - a: 313283 + a: 14396347928 b: 0 c: 0 - d: 0 + d: 6148914694092305796 Addr: bp00.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Leader -- ID: 00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35 +- ID: 000000000013fd4b3180dd424d5a895bc57b798e5315087b7198c926d8893f98 Nonce: - a: 478373 + a: 789554103 b: 0 c: 0 - d: 2305843009893772025 + d: 8070450536379825883 Addr: bp01.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Follower -- ID: 000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582 +- ID: 00000000001771e2b2e12b6f9f85d58ef5261a4b98a2e80bba0c5ef7bd72c499 Nonce: - a: 259939 + a: 1822880492 b: 0 c: 0 - d: 2305843012544226372 + d: 8646911286604382906 Addr: bp02.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 000000000014a2f14e79aec0a27a2a669aab416c392d5577760d43ed8503020d + Nonce: + a: 2552803966 + b: 0 + c: 0 + d: 9079256850862786277 + Addr: bp03.cn.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 00000000003b2bd120a7d07f248b181fc794ba8b278f07f9a780e61eb77f6abb + Nonce: + a: 2449538793 + b: 0 + c: 0 + d: 8791026473473316840 + Addr: bp04.hk.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 0000000000293f7216362791b6b1c9772184d6976cb34310c42547735410186c + Nonce: + a: 746598970 + b: 0 + c: 0 + d: 10808639108098016056 + Addr: bp05.cn.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Follower - ID: 00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d Nonce: diff --git a/conf/testnet/parameters.go b/conf/testnet/parameters.go index e4f0ad3d8..1d490b2e3 100644 --- a/conf/testnet/parameters.go +++ b/conf/testnet/parameters.go @@ -34,7 +34,7 @@ DHTFileName: "dht.db" ListenAddr: "0.0.0.0:15151" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 60 +BillingBlockCount: 60 BPPeriod: 10s BPTick: 3s SQLChainPeriod: 60s @@ -55,13 +55,13 @@ DNSSeed: - 202.46.34.76 BlockProducer: - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" - NodeID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + NodeID: 00000000000589366268c274fdc11ec8bdb17e668d2f619555a2e9c1a29c91d8 Nonce: - a: 313283 + a: 14396347928 b: 0 c: 0 - d: 0 + d: 6148914694092305796 ChainFileName: "chain.db" BPGenesisInfo: Version: 1 @@ -69,7 +69,7 @@ BlockProducer: Producer: 0000000000000000000000000000000000000000000000000000000000000001 MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 - Timestamp: 2018-12-28T12:20:59.12Z + Timestamp: 2019-01-02T13:33:00.00Z BaseAccounts: - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 StableCoinBalance: 10000000000000000000 @@ -83,33 +83,63 @@ BlockProducer: - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd StableCoinBalance: 10000000000000000000 CovenantCoinBalance: 10000000000000000000 + - Address: 58aceaf4b730b54bf00c0fb3f7b14886de470767f313c2d108968cd8bf0794b7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 KnownNodes: -- ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 +- ID: 00000000000589366268c274fdc11ec8bdb17e668d2f619555a2e9c1a29c91d8 Nonce: - a: 313283 + a: 14396347928 b: 0 c: 0 - d: 0 + d: 6148914694092305796 Addr: bp00.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Leader -- ID: 00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35 +- ID: 000000000013fd4b3180dd424d5a895bc57b798e5315087b7198c926d8893f98 Nonce: - a: 478373 + a: 789554103 b: 0 c: 0 - d: 2305843009893772025 + d: 8070450536379825883 Addr: bp01.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Follower -- ID: 000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582 +- ID: 00000000001771e2b2e12b6f9f85d58ef5261a4b98a2e80bba0c5ef7bd72c499 Nonce: - a: 259939 + a: 1822880492 b: 0 c: 0 - d: 2305843012544226372 + d: 8646911286604382906 Addr: bp02.cn.gridb.io:7777 - PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 000000000014a2f14e79aec0a27a2a669aab416c392d5577760d43ed8503020d + Nonce: + a: 2552803966 + b: 0 + c: 0 + d: 9079256850862786277 + Addr: bp03.cn.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 00000000003b2bd120a7d07f248b181fc794ba8b278f07f9a780e61eb77f6abb + Nonce: + a: 2449538793 + b: 0 + c: 0 + d: 8791026473473316840 + Addr: bp04.hk.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" + Role: Follower +- ID: 0000000000293f7216362791b6b1c9772184d6976cb34310c42547735410186c + Nonce: + a: 746598970 + b: 0 + c: 0 + d: 10808639108098016056 + Addr: bp05.cn.gridb.io:7777 + PublicKey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c" Role: Follower - ID: 000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade Nonce: @@ -128,7 +158,17 @@ KnownNodes: d: 2305843010430351476 Addr: miner01.cn.gridb.io:7778 PublicKey: 02914bca0806f040dd842207c44474ab41ecd29deee7f2d355789c5c78d448ca16 - Role: Miner` + Role: Miner +- ID: 00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d + Nonce: + a: 22403 + b: 0 + c: 0 + d: 0 + Addr: "" + PublicKey: 02ec784ca599f21ef93fe7abdc68d78817ab6c9b31f2324d15ea174d9da498b4c4 + Role: Client +` ) // GetTestNetConfig parses and returns the CovenantSQL TestNet config. diff --git a/crypto/address.go b/crypto/address.go index 5f09b72e1..25f6f6f02 100644 --- a/crypto/address.go +++ b/crypto/address.go @@ -20,29 +20,9 @@ import ( "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/proto" - "github.com/btcsuite/btcutil/base58" "github.com/pkg/errors" ) -const ( - // MainNet is the version byte for main net. - MainNet byte = 0x0 - // TestNet is the version byte for test net. - TestNet byte = 0x6f -) - -// PubKey2Addr converts the pubKey to a address -// and the format refers to https://bitcoin.org/en/developer-guide#standard-transactions -func PubKey2Addr(pubKey *asymmetric.PublicKey, version byte) (addr string, err error) { - var internalAddr proto.AccountAddress - if internalAddr, err = PubKeyHash(pubKey); err != nil { - return - } - - addr = Hash2Addr(internalAddr, version) - return -} - // PubKeyHash generates the account hash address for specified public key. func PubKeyHash(pubKey *asymmetric.PublicKey) (addr proto.AccountAddress, err error) { if pubKey == nil { @@ -58,22 +38,3 @@ func PubKeyHash(pubKey *asymmetric.PublicKey) (addr proto.AccountAddress, err er addr = proto.AccountAddress(hash.THashH(enc)) return } - -// Addr2Hash converts base58 address to internal account address hash. -func Addr2Hash(addr string) (version byte, internalAddr proto.AccountAddress, err error) { - var hashBytes []byte - if hashBytes, version, err = base58.CheckDecode(addr); err != nil { - return - } - var h *hash.Hash - if h, err = hash.NewHash(hashBytes); err != nil { - return - } - internalAddr = proto.AccountAddress(*h) - return -} - -// Hash2Addr converts interal account address hash to base58 format. -func Hash2Addr(addr proto.AccountAddress, version byte) string { - return base58.CheckEncode(addr[:], version) -} diff --git a/crypto/address_test.go b/crypto/address_test.go index 738ed96eb..b3bea1b0a 100644 --- a/crypto/address_test.go +++ b/crypto/address_test.go @@ -17,88 +17,48 @@ package crypto import ( - "encoding/base64" + "encoding/hex" "testing" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" - "github.com/btcsuite/btcutil/base58" . "github.com/smartystreets/goconvey/convey" ) func TestPubKeyHashAndAddressing(t *testing.T) { testPubkeyAndAddr := []struct { - pubkey string - addr string - nettype byte + pubkey string + addr string }{ { - pubkey: "AwVygZRpvwCc+8SKnbwQrtlXPze7/hte0ksObyml37Gi", - addr: "1EcL9WYyB59jVLSX9kxFdfY53aDoWAKSFRkwwV2cvMMNCWj81J", - nettype: MainNet, + pubkey: "0367aa51809a7c1dc0f82c02452fec9557b3e1d10ce7c919d8e73d90048df86d20", + addr: "ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37", }, { - pubkey: "AwVygZRpvwCc+8SKnbwQrtlXPze7/hte0ksObyml37Gi", - addr: "4j1EutL6ZQ9HhYqj9Ves8EDVihvvxfhWnCHi2ZqXxf6Q9GK45v5", - nettype: TestNet, + pubkey: "02914bca0806f040dd842207c44474ab41ecd29deee7f2d355789c5c78d448ca16", + addr: "1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be", }, { - pubkey: "Aua4icZ7gvBbzw4MDkGvFOEXG88lY4IJccigDQRghj1c", - addr: "12HRffwitkFR4ooMu6x5EAnHscKyftfuTZnTc3ciYmoSh9HxMY5", - nettype: MainNet, + pubkey: "02ec784ca599f21ef93fe7abdc68d78817ab6c9b31f2324d15ea174d9da498b4c4", + addr: "9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd", }, { - pubkey: "Aua4icZ7gvBbzw4MDkGvFOEXG88lY4IJccigDQRghj1c", - addr: "4k44FQmGUyKZ2sJeXSqz6mLFXGggq4D6oWeQgfyDtWYVUDQS2bj", - nettype: TestNet, + pubkey: "03ae859eac5b72ee428c7a85f10b2ce748d9de5e480aefbb70f6597dfa8b2175e5", + addr: "9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16", }, { - pubkey: "An/n4w2Lb3QYPzpQjAlADcK14LnwDbkl21gdasuwND1a", - addr: "1FinCZcguUux4fxM5dJuuGCUNRTw49Dx26KnAzA8Kh4djuHeH2", - nettype: MainNet, - }, - { - pubkey: "An/n4w2Lb3QYPzpQjAlADcK14LnwDbkl21gdasuwND1a", - addr: "4j2MMwPAH8Z3v8BEyRXDnVpA82nB6DgRHxxGroLfU4S7Qk5k9vQ", - nettype: TestNet, + pubkey: "02c1db96f2ba7e1cb4e9822d12de0f63fb666feb828c7f509e81fab9bd7a34039c", + addr: "58aceaf4b730b54bf00c0fb3f7b14886de470767f313c2d108968cd8bf0794b7", }, } Convey("Test the public key and address", t, func() { for i := range testPubkeyAndAddr { - pubByte, err := base64.StdEncoding.DecodeString(testPubkeyAndAddr[i].pubkey) - So(err, ShouldBeNil) - pub, err := asymmetric.ParsePubKey(pubByte) - addr, err := PubKey2Addr(pub, testPubkeyAndAddr[i].nettype) - So(addr, ShouldEqual, testPubkeyAndAddr[i].addr) - } - }) - - Convey("Randomly generate some key pairs and calculate public key hash values", t, func() { - for i := 0; i < 20; i++ { - _, pub, err := asymmetric.GenSecp256k1KeyPair() - So(err, ShouldBeNil) - h, err := PubKeyHash(pub) + pubByte, err := hex.DecodeString(testPubkeyAndAddr[i].pubkey) So(err, ShouldBeNil) - addr, err := PubKey2Addr(pub, MainNet) + pub, _ := asymmetric.ParsePubKey(pubByte) + addr, err := PubKeyHash(pub) + So(addr.String(), ShouldEqual, testPubkeyAndAddr[i].addr) So(err, ShouldBeNil) - targetAddr := base58.CheckEncode(h[:], MainNet) - So(addr, ShouldEqual, targetAddr) - t.Logf("main net address: %s", targetAddr) - - addr, err = PubKey2Addr(pub, TestNet) - So(err, ShouldBeNil) - targetAddr = base58.CheckEncode(h[:], TestNet) - So(err, ShouldBeNil) - t.Logf("test net address: %s", targetAddr) } }) - - Convey("Test Hash/Addr bi-directional convert", t, func() { - version, internalAddr, err := Addr2Hash("4j2MMwPAH8Z3v8BEyRXDnVpA82nB6DgRHxxGroLfU4S7Qk5k9vQ") - So(version, ShouldEqual, TestNet) - So(err, ShouldBeNil) - - addr := Hash2Addr(internalAddr, MainNet) - So(addr, ShouldEqual, "1FinCZcguUux4fxM5dJuuGCUNRTw49Dx26KnAzA8Kh4djuHeH2") - }) } diff --git a/crypto/asymmetric/signature.go b/crypto/asymmetric/signature.go index ec7e59804..ee3a02b9a 100644 --- a/crypto/asymmetric/signature.go +++ b/crypto/asymmetric/signature.go @@ -20,7 +20,6 @@ import ( "crypto/elliptic" "errors" "math/big" - "sync" "github.com/CovenantSQL/CovenantSQL/crypto/secp256k1" "github.com/CovenantSQL/CovenantSQL/utils" @@ -32,7 +31,6 @@ var ( // BypassSignature is the flag indicate if bypassing signature sign & verify BypassSignature = false bypassS *Signature - mu sync.Mutex ) // For test Signature.Sign mock diff --git a/crypto/hash/hashfuncs.go b/crypto/hash/hashfuncs.go index d3cd98561..af14cf46d 100644 --- a/crypto/hash/hashfuncs.go +++ b/crypto/hash/hashfuncs.go @@ -19,6 +19,7 @@ package hash import ( "encoding/binary" "hash/fnv" + // "crypto/sha256" benchmark is at least 10% faster on // i7-4870HQ CPU @ 2.50GHz than "github.com/minio/sha256-simd" "crypto/sha256" diff --git a/crypto/kms/privatekeystore.go b/crypto/kms/privatekeystore.go index 0e3aa01d8..1b2a6fdfe 100644 --- a/crypto/kms/privatekeystore.go +++ b/crypto/kms/privatekeystore.go @@ -37,21 +37,32 @@ var ( ErrHashNotMatch = errors.New("private key hash not match") // ErrInvalidBase58Version indicates specified key is not base58 version ErrInvalidBase58Version = errors.New("invalid base58 version") - // ErrInvalidBase58Checksum indicates specified key checksum is not base58 checksum - ErrInvalidBase58Checksum = errors.New("invalid base58 checksum") // PrivateKeyStoreVersion defines the private key version byte. PrivateKeyStoreVersion byte = 0x23 + // oldPrivateKDFSalt is the old KDF salt for private key encryption + oldPrivateKDFSalt = "auxten-key-salt-auxten" + // privateKDFSalt is the KDF salt for private key encryption + privateKDFSalt = []byte{ + 0xC0, 0x4E, 0xA4, 0x71, 0x49, 0x65, 0x41, 0x31, + 0x79, 0x4b, 0x6a, 0x70, 0x2f, 0x39, 0x45, 0x43, + } ) // LoadPrivateKey loads private key from keyFilePath, and verifies the hash // head func LoadPrivateKey(keyFilePath string, masterKey []byte) (key *asymmetric.PrivateKey, err error) { + var ( + isBinaryKey bool + decData []byte + ) fileContent, err := ioutil.ReadFile(keyFilePath) if err != nil { log.WithField("path", keyFilePath).WithError(err).Error("read key file failed") return } + // It's very impossible to get an raw private key base58 decodable. + // So if it's not base58 decodable we just make fileContent the encData encData, version, err := base58.CheckDecode(string(fileContent)) switch err { case base58.ErrChecksum: @@ -59,6 +70,7 @@ func LoadPrivateKey(keyFilePath string, masterKey []byte) (key *asymmetric.Priva case base58.ErrInvalidFormat: // be compatible with the original binary private key format + isBinaryKey = true encData = fileContent } @@ -66,27 +78,45 @@ func LoadPrivateKey(keyFilePath string, masterKey []byte) (key *asymmetric.Priva return nil, ErrInvalidBase58Version } - decData, err := symmetric.DecryptWithPassword(encData, masterKey) - if err != nil { - log.Error("decrypt private key error") - return - } + if isBinaryKey { + decData, err = symmetric.DecryptWithPassword(encData, masterKey, []byte(oldPrivateKDFSalt)) + if err != nil { + log.Error("decrypt private key error") + return + } - // sha256 + privateKey - if len(decData) != hash.HashBSize+asymmetric.PrivateKeyBytesLen { - log.WithFields(log.Fields{ - "expected": hash.HashBSize + asymmetric.PrivateKeyBytesLen, - "actual": len(decData), - }).Error("wrong private key file size") - return nil, ErrNotKeyFile - } + // sha256 + privateKey + if len(decData) != hash.HashBSize+asymmetric.PrivateKeyBytesLen { + log.WithFields(log.Fields{ + "expected": hash.HashBSize + asymmetric.PrivateKeyBytesLen, + "actual": len(decData), + }).Error("wrong binary private key file size") + return nil, ErrNotKeyFile + } + + computedHash := hash.DoubleHashB(decData[hash.HashBSize:]) + if !bytes.Equal(computedHash, decData[:hash.HashBSize]) { + return nil, ErrHashNotMatch + } + key, _ = asymmetric.PrivKeyFromBytes(decData[hash.HashBSize:]) + } else { + decData, err = symmetric.DecryptWithPassword(encData, masterKey, privateKDFSalt) + if err != nil { + log.Error("decrypt private key error") + return + } - computedHash := hash.DoubleHashB(decData[hash.HashBSize:]) - if !bytes.Equal(computedHash, decData[:hash.HashBSize]) { - return nil, ErrHashNotMatch + // privateKey + if len(decData) != asymmetric.PrivateKeyBytesLen { + log.WithFields(log.Fields{ + "expected": asymmetric.PrivateKeyBytesLen, + "actual": len(decData), + }).Error("wrong base58 private key file size") + return nil, ErrNotKeyFile + } + key, _ = asymmetric.PrivKeyFromBytes(decData) } - key, _ = asymmetric.PrivKeyFromBytes(decData[hash.HashBSize:]) return } @@ -94,9 +124,7 @@ func LoadPrivateKey(keyFilePath string, masterKey []byte) (key *asymmetric.Priva // default perm is 0600 func SavePrivateKey(keyFilePath string, key *asymmetric.PrivateKey, masterKey []byte) (err error) { serializedKey := key.Serialize() - keyHash := hash.DoubleHashB(serializedKey) - rawData := append(keyHash, serializedKey...) - encKey, err := symmetric.EncryptWithPassword(rawData, masterKey) + encKey, err := symmetric.EncryptWithPassword(serializedKey, masterKey, privateKDFSalt) if err != nil { return } diff --git a/crypto/kms/privatekeystore_test.go b/crypto/kms/privatekeystore_test.go index 32710e0df..c33ba450f 100644 --- a/crypto/kms/privatekeystore_test.go +++ b/crypto/kms/privatekeystore_test.go @@ -34,6 +34,7 @@ import ( const ( privateKeyPath = "./.testprivatekey" password = "auxten" + salt = "auxten-key-salt-auxten" ) func TestSaveLoadPrivateKey(t *testing.T) { @@ -83,7 +84,7 @@ func TestLoadPrivateKey(t *testing.T) { }) Convey("not key file2", t, func() { defer os.Remove("./.notkey") - enc, _ := symmetric.EncryptWithPassword([]byte("aa"), []byte(password)) + enc, _ := symmetric.EncryptWithPassword([]byte("aa"), []byte(password), []byte(salt)) ioutil.WriteFile("./.notkey", enc, 0600) lk, err := LoadPrivateKey("./.notkey", []byte(password)) So(err, ShouldEqual, ErrNotKeyFile) @@ -91,7 +92,7 @@ func TestLoadPrivateKey(t *testing.T) { }) Convey("hash not match", t, func() { defer os.Remove("./.HashNotMatch") - enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 64), []byte(password)) + enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 64), []byte(password), []byte(salt)) ioutil.WriteFile("./.HashNotMatch", enc, 0600) lk, err := LoadPrivateKey("./.HashNotMatch", []byte(password)) So(err, ShouldEqual, ErrHashNotMatch) @@ -105,7 +106,7 @@ func TestLoadPrivateKey(t *testing.T) { serializedKey := privateKey.Serialize() keyHash := hash.DoubleHashB(serializedKey) rawData := append(keyHash, serializedKey...) - encKey, _ := symmetric.EncryptWithPassword(rawData, []byte(password)) + encKey, _ := symmetric.EncryptWithPassword(rawData, []byte(password), []byte(salt)) invalidBase58EncKey := base58.CheckEncode(encKey, invalidPrivateKeyStoreVersion) ioutil.WriteFile("./.Base58VersionNotMatch", []byte(invalidBase58EncKey), 0600) lk, err := LoadPrivateKey("./.Base58VersionNotMatch", []byte(password)) @@ -154,14 +155,14 @@ func TestInitLocalKeyPair(t *testing.T) { func TestInitLocalKeyPair_error(t *testing.T) { Convey("hash not match", t, func() { defer os.Remove("./.HashNotMatch") - enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 64), []byte(password)) + enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 64), []byte(password), []byte(salt)) ioutil.WriteFile("./.HashNotMatch", enc, 0600) err := InitLocalKeyPair("./.HashNotMatch", []byte(password)) So(err, ShouldEqual, ErrHashNotMatch) }) Convey("ErrNotKeyFile", t, func() { defer os.Remove("./.ErrNotKeyFile") - enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 65), []byte(password)) + enc, _ := symmetric.EncryptWithPassword(bytes.Repeat([]byte("a"), 65), []byte(password), []byte(salt)) ioutil.WriteFile("./.ErrNotKeyFile", enc, 0600) err := InitLocalKeyPair("./.ErrNotKeyFile", []byte(password)) So(err, ShouldEqual, ErrNotKeyFile) diff --git a/crypto/kms/pubkeystore.go b/crypto/kms/pubkeystore.go index 550882960..2719a707c 100644 --- a/crypto/kms/pubkeystore.go +++ b/crypto/kms/pubkeystore.go @@ -101,8 +101,6 @@ var ( ErrNilNode = errors.New("nil node") // ErrKeyNotFound indicates key not found ErrKeyNotFound = errors.New("key not found") - // ErrNotValidNodeID indicates that is not valid node id - ErrNotValidNodeID = errors.New("not valid node id") // ErrNodeIDKeyNonceNotMatch indicates node id, key, nonce not match ErrNodeIDKeyNonceNotMatch = errors.New("nodeID, key, nonce not match") ) diff --git a/crypto/symmetric/aes.go b/crypto/symmetric/aes.go index 41c7a0f1d..afaeef8ed 100644 --- a/crypto/symmetric/aes.go +++ b/crypto/symmetric/aes.go @@ -28,10 +28,6 @@ import ( "github.com/CovenantSQL/CovenantSQL/crypto/hash" ) -const ( - keySalt = "auxten-key-salt-auxten" -) - var ( // ErrInputSize indicates cipher data size is not expected, // maybe data is not encrypted by EncryptWithPassword in this package @@ -39,16 +35,16 @@ var ( ) // keyDerivation does sha256 twice to password -func keyDerivation(password []byte) (out []byte) { - return hash.DoubleHashB(append(password, keySalt...)) +func keyDerivation(password []byte, salt []byte) (out []byte) { + return hash.DoubleHashB(append(password, salt...)) } // EncryptWithPassword encrypts data with given password, iv will be placed // at head of cipher data -func EncryptWithPassword(in, password []byte) (out []byte, err error) { +func EncryptWithPassword(in, password []byte, salt []byte) (out []byte, err error) { // keyE will be 256 bits, so aes.NewCipher(keyE) will return // AES-256 Cipher. - keyE := keyDerivation(password) + keyE := keyDerivation(password, salt) paddedIn := crypto.AddPKCSPadding(in) // IV + padded cipher data out = make([]byte, aes.BlockSize+len(paddedIn)) @@ -70,8 +66,8 @@ func EncryptWithPassword(in, password []byte) (out []byte, err error) { } // DecryptWithPassword decrypts data with given password -func DecryptWithPassword(in, password []byte) (out []byte, err error) { - keyE := keyDerivation(password) +func DecryptWithPassword(in, password []byte, salt []byte) (out []byte, err error) { + keyE := keyDerivation(password, salt) // IV + padded cipher data == (n + 1 + 1) * aes.BlockSize if len(in)%aes.BlockSize != 0 || len(in)/aes.BlockSize < 2 { return nil, ErrInputSize diff --git a/crypto/symmetric/aes_test.go b/crypto/symmetric/aes_test.go index a5054dff1..4c469015b 100644 --- a/crypto/symmetric/aes_test.go +++ b/crypto/symmetric/aes_test.go @@ -24,16 +24,19 @@ import ( . "github.com/smartystreets/goconvey/convey" ) -const password = "CovenantSQL.io" +const ( + password = "CovenantSQL.io" + salt = "auxten-key-salt-auxten" +) func TestEncryptDecryptWithPassword(t *testing.T) { Convey("encrypt & decrypt 0 length bytes with aes256", t, func() { - enc, err := EncryptWithPassword([]byte(nil), []byte(password)) + enc, err := EncryptWithPassword([]byte(nil), []byte(password), []byte(salt)) So(enc, ShouldNotBeNil) So(len(enc), ShouldEqual, 2*aes.BlockSize) So(err, ShouldBeNil) - dec, err := DecryptWithPassword(enc, []byte(password)) + dec, err := DecryptWithPassword(enc, []byte(password), []byte(salt)) So(dec, ShouldNotBeNil) So(len(dec), ShouldEqual, 0) So(err, ShouldBeNil) @@ -41,12 +44,12 @@ func TestEncryptDecryptWithPassword(t *testing.T) { Convey("encrypt & decrypt 1747 length bytes", t, func() { in := bytes.Repeat([]byte{0xff}, 1747) - enc, err := EncryptWithPassword(in, []byte(password)) + enc, err := EncryptWithPassword(in, []byte(password), []byte(salt)) So(enc, ShouldNotBeNil) So(len(enc), ShouldEqual, (1747/aes.BlockSize+2)*aes.BlockSize) So(err, ShouldBeNil) - dec, err := DecryptWithPassword(enc, []byte(password)) + dec, err := DecryptWithPassword(enc, []byte(password), []byte(salt)) So(dec, ShouldNotBeNil) So(len(dec), ShouldEqual, 1747) So(err, ShouldBeNil) @@ -54,7 +57,7 @@ func TestEncryptDecryptWithPassword(t *testing.T) { Convey("decrypt error length bytes", t, func() { in := bytes.Repeat([]byte{0xff}, 1747) - dec, err := DecryptWithPassword(in, []byte(password)) + dec, err := DecryptWithPassword(in, []byte(password), []byte(salt)) So(dec, ShouldBeNil) So(err, ShouldEqual, ErrInputSize) }) diff --git a/docker-compose.yml b/docker-compose.yml index e4b1fdf5d..592c67902 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -131,30 +131,6 @@ services: networks: default: ipv4_address: 172.254.1.8 - covenantsql_observer: - image: covenantsql/covenantsql:latest - container_name: covenantsql_observer - restart: always - ports: - - "11106:4663" - command: - [ - "-listen", - "0.0.0.0:4663", - ] - environment: - COVENANT_ROLE: observer - COVENANT_CONF: ./node_observer/config.yaml - volumes: - - ./test/service/node_observer/:/app/node_observer/ - networks: - default: - ipv4_address: 172.254.1.9 - logging: - driver: "json-file" - options: - max-size: "1m" - max-file: "10" covenantsql_mysql_adapter: image: covenantsql/covenantsql:latest container_name: covenantsql_mysql_adapter @@ -175,20 +151,26 @@ services: options: max-size: "1m" max-file: "10" - covenantsql_explorer: - image: covenantsql/explorer:latest - container_name: covenantsql_explorer - depends_on: - - covenantsql_observer + covenantsql_observer: + image: covenantsql/covenantsql-observer:latest + container_name: covenantsql_observer restart: always ports: - "11108:80" environment: + COVENANT_ROLE: observer + COVENANT_CONF: ./node_observer/config.yaml COVENANTSQL_EXPLORER_DOMAIN: localhost - COVENANTSQL_OBSERVER_ADDR: covenantsql_observer:4663 + COVENANTSQL_OBSERVER_ADDR: localhost:4663 + volumes: + - ./test/service/node_observer/:/app/node_observer/ + networks: + default: + ipv4_address: 172.254.1.9 logging: + driver: "json-file" options: - max-size: "5m" + max-size: "10m" networks: default: diff --git a/Dockerfile b/docker/Dockerfile similarity index 60% rename from Dockerfile rename to docker/Dockerfile index b2f1a82f5..c5e2027ac 100644 --- a/Dockerfile +++ b/docker/Dockerfile @@ -1,12 +1,4 @@ -# Stage: builder -FROM golang:1.11-stretch as builder - -WORKDIR /go/src/github.com/CovenantSQL/CovenantSQL -COPY . . -RUN GOOS=linux GOLDFLAGS="-linkmode external -extldflags -static" ./build.sh -RUN rm -f bin/*.test - -# Stage: runner +# Stage: all runner FROM frolvlad/alpine-glibc:latest ARG COMMIT @@ -27,6 +19,6 @@ ENV COVENANT_CONF=config.yaml RUN apk --no-cache add ca-certificates WORKDIR /app -COPY --from=builder /go/src/github.com/CovenantSQL/CovenantSQL/bin/* /app/ +COPY --from=covenantsql/covenantsql-builder /go/src/github.com/CovenantSQL/CovenantSQL/bin/* /app/ ENTRYPOINT [ "./docker-entry.sh" ] EXPOSE 4661 diff --git a/docker/builder.Dockerfile b/docker/builder.Dockerfile new file mode 100644 index 000000000..650b884d3 --- /dev/null +++ b/docker/builder.Dockerfile @@ -0,0 +1,11 @@ +# Stage: builder +FROM golang:1.11-stretch as builder + +ARG BUILD_ARG + +WORKDIR /go/src/github.com/CovenantSQL/CovenantSQL +COPY . . +RUN make clean +RUN GOOS=linux GOLDFLAGS="-linkmode external -extldflags -static" make ${BUILD_ARG} +RUN rm -f bin/*.test + diff --git a/docker/observer.Dockerfile b/docker/observer.Dockerfile new file mode 100644 index 000000000..6e37949b2 --- /dev/null +++ b/docker/observer.Dockerfile @@ -0,0 +1,26 @@ +# Stage: observer +FROM covenantsql/explorer + +ARG COMMIT +ARG VERSION + +LABEL \ + name="covenantsql_observer" \ + homepage="https://github.com/CovenantSQL/CovenantSQL.git" \ + maintainer="jin.xu@covenantsql.io" \ + authors="CovenantSQL Team" \ + commit="${COMMIT}" \ + version="${VERSION}" + +ENV VERSION=${VERSION} +ENV COVENANT_ROLE=observer +ENV COVENANT_CONF=config.yaml + +RUN apk --no-cache add ca-certificates + +WORKDIR /app +COPY --from=covenantsql/covenantsql-builder /go/src/github.com/CovenantSQL/CovenantSQL/bin/cql-observer /app/ +COPY --from=covenantsql/covenantsql-builder /go/src/github.com/CovenantSQL/CovenantSQL/bin/docker-entry.sh /app/ +ENTRYPOINT [ "./docker-entry.sh" ] +EXPOSE 4661 +EXPOSE 80 diff --git a/kayak/types/errors.go b/kayak/types/errors.go index 6ceab9c9d..2912207d7 100644 --- a/kayak/types/errors.go +++ b/kayak/types/errors.go @@ -31,8 +31,6 @@ var ( ErrInvalidLog = errors.New("invalid log") // ErrNotInPeer represents current node does not exists in peer list. ErrNotInPeer = errors.New("node not in peer") - // ErrNeedRecovery represents current follower node needs recovery, back-off is required by leader. - ErrNeedRecovery = errors.New("need recovery") // ErrInvalidConfig represents invalid kayak runtime config. ErrInvalidConfig = errors.New("invalid runtime config") ) diff --git a/kayak/wal/leveldb_wal.go b/kayak/wal/leveldb_wal.go index 8382744de..374d1f45b 100644 --- a/kayak/wal/leveldb_wal.go +++ b/kayak/wal/leveldb_wal.go @@ -190,17 +190,6 @@ func (p *LevelDBWal) Close() { } } -// GetDB returns the leveldb for storage extensions. -func (p *LevelDBWal) GetDB() (d *leveldb.DB, err error) { - if atomic.LoadUint32(&p.closed) == 1 { - err = ErrWalClosed - return - } - - d = p.db - return -} - func (p *LevelDBWal) load(logHeader []byte) (l *kt.Log, err error) { l = new(kt.Log) diff --git a/route/acl.go b/route/acl.go index 2abcc9ad9..f62cb403e 100644 --- a/route/acl.go +++ b/route/acl.go @@ -115,12 +115,10 @@ const ( MCCNextAccountNonce // MCCAddTx is used by block producer main chain to upload transaction MCCAddTx - // MCCQueryAccountStableBalance is used by block producer to provide account stable coin balance - MCCQueryAccountStableBalance - // MCCQueryAccountCovenantBalance is used by block producer to provide account covenant coin balance - MCCQueryAccountCovenantBalance // MCCQuerySQLChainProfile is used by nodes to to query SQLChainProfile. MCCQuerySQLChainProfile + // MCCQueryAccountTokenBalance is used by block producer to provide account token balance + MCCQueryAccountTokenBalance // DHTRPCName defines the block producer dh-rpc service name DHTRPCName = "DHT" // BlockProducerRPCName defines main chain rpc name @@ -192,12 +190,10 @@ func (s RemoteFunc) String() string { return "MCC.NextAccountNonce" case MCCAddTx: return "MCC.AddTx" - case MCCQueryAccountStableBalance: - return "MCC.QueryAccountStableBalance" - case MCCQueryAccountCovenantBalance: - return "MCC.QueryAccountCovenantBalance" case MCCQuerySQLChainProfile: return "MCC.QuerySQLChainProfile" + case MCCQueryAccountTokenBalance: + return "MCC.QueryAccountTokenBalance" } return "Unknown" } diff --git a/rpc/client_test.go b/rpc/client_test.go index ecdf30f1b..c57e1dc0c 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -26,9 +26,7 @@ import ( ) const nodeID = "0000" -const privateKey = "test.private" const publicKeyStore = "./test.keystore" -const pass = "abc" func TestDial(t *testing.T) { Convey("dial error case", t, func() { diff --git a/rpc/rpcutil_test.go b/rpc/rpcutil_test.go index 13c786a28..00c51c87f 100644 --- a/rpc/rpcutil_test.go +++ b/rpc/rpcutil_test.go @@ -37,7 +37,6 @@ import ( ) const ( - DHTStorePath = "./DHTStore" RPCConcurrent = 10 RPCCount = 100 ) diff --git a/sqlchain/chain.go b/sqlchain/chain.go index 76e4f8a00..cd314ef99 100644 --- a/sqlchain/chain.go +++ b/sqlchain/chain.go @@ -52,7 +52,6 @@ const ( var ( metaState = [4]byte{'S', 'T', 'A', 'T'} metaBlockIndex = [4]byte{'B', 'L', 'C', 'K'} - metaRequestIndex = [4]byte{'R', 'E', 'Q', 'U'} metaResponseIndex = [4]byte{'R', 'E', 'S', 'P'} metaAckIndex = [4]byte{'Q', 'A', 'C', 'K'} leveldbConf = opt.Options{} @@ -79,11 +78,6 @@ func heightToKey(h int32) (key []byte) { return } -// keyToHeight converts a height back from a key in bytes. -func keyToHeight(k []byte) int32 { - return int32(binary.BigEndian.Uint32(k)) -} - // keyWithSymbolToHeight converts a height back from a key(ack/resp/req/block) in bytes. // ack key: // ['Q', 'A', 'C', 'K', height, hash] @@ -1108,241 +1102,6 @@ func (c *Chain) UpdatePeers(peers *proto.Peers) error { return c.rt.updatePeers(peers) } -// getBilling returns a billing request from the blocks within height range [low, high]. -func (c *Chain) getBilling(low, high int32) (req *types.BillingRequest, err error) { - // Height `n` is ensured (or skipped) if `Next Turn` > `n` + 1 - if c.rt.getNextTurn() <= high+1 { - err = ErrUnavailableBillingRang - return - } - - var ( - n *blockNode - addr proto.AccountAddress - lowBlock, highBlock *types.Block - billings = make(map[proto.AccountAddress]*proto.AddrAndGas) - ) - - if head := c.rt.getHead(); head != nil { - n = head.node - } - - for ; n != nil && n.height > high; n = n.parent { - } - - for ; n != nil && n.height >= low; n = n.parent { - // TODO(leventeliu): block maybe released, use persistence version in this case. - if n.block == nil { - continue - } - - if lowBlock == nil { - lowBlock = n.block - } - - highBlock = n.block - - if addr, err = crypto.PubKeyHash(n.block.Signee()); err != nil { - return - } - - if billing, ok := billings[addr]; ok { - billing.GasAmount = c.rt.producingReward - } else { - producer := n.block.Producer() - billings[addr] = &proto.AddrAndGas{ - AccountAddress: addr, - RawNodeID: *producer.ToRawNodeID(), - GasAmount: c.rt.producingReward, - } - } - - for _, v := range n.block.Acks { - if addr, err = crypto.PubKeyHash(v.SignedResponseHeader().Signee); err != nil { - return - } - - if billing, ok := billings[addr]; ok { - billing.GasAmount += c.rt.price[v.SignedRequestHeader().QueryType] * - v.SignedRequestHeader().BatchCount - } else { - billings[addr] = &proto.AddrAndGas{ - AccountAddress: addr, - RawNodeID: *v.SignedResponseHeader().NodeID.ToRawNodeID(), - GasAmount: c.rt.producingReward, - } - } - } - } - - if lowBlock == nil || highBlock == nil { - err = ErrUnavailableBillingRang - return - } - - // Make request - gasAmounts := make([]*proto.AddrAndGas, 0, len(billings)) - - for _, v := range billings { - gasAmounts = append(gasAmounts, v) - } - - req = &types.BillingRequest{ - Header: types.BillingRequestHeader{ - DatabaseID: c.databaseID, - LowBlock: *lowBlock.BlockHash(), - LowHeight: low, - HighBlock: *highBlock.BlockHash(), - HighHeight: high, - GasAmounts: gasAmounts, - }, - } - return -} - -func (c *Chain) collectBillingSignatures(ctx context.Context, billings *types.BillingRequest) { - // Process sign billing responses, note that range iterating over channel will only break if - // the channel is closed - req := &MuxSignBillingReq{ - Envelope: proto.Envelope{ - // TODO(leventeliu): Add fields. - }, - DatabaseID: c.databaseID, - SignBillingReq: SignBillingReq{ - BillingRequest: *billings, - }, - } - proWG := &sync.WaitGroup{} - respC := make(chan *SignBillingResp) - defer proWG.Wait() - proWG.Add(1) - go func() { - defer proWG.Done() - - bpReq := &types.AdviseBillingReq{ - Req: billings, - } - - var ( - bpNodeID proto.NodeID - err error - ) - - for resp := range respC { - if err = bpReq.Req.AddSignature(resp.Signee, resp.Signature, false); err != nil { - // consume all rpc result - for range respC { - } - - return - } - } - - defer log.WithFields(log.Fields{ - "peer": c.rt.getPeerInfoString(), - "time": c.rt.getChainTimeString(), - "signees_count": len(req.Signees), - "signatures_count": len(req.Signatures), - "bp": bpNodeID, - }).WithError(err).Debug( - "Sent billing request") - - if bpNodeID, err = rpc.GetCurrentBP(); err != nil { - return - } - - var resp interface{} - if err = c.cl.CallNodeWithContext( - ctx, bpNodeID, route.MCCAdviseBillingRequest.String(), bpReq, resp, - ); err != nil { - return - } - }() - - // Send requests and push responses to response channel - peers := c.rt.getPeers() - rpcWG := &sync.WaitGroup{} - defer func() { - rpcWG.Wait() - close(respC) - }() - - for _, s := range peers.Servers { - if s != c.rt.getServer() { - rpcWG.Add(1) - go func(id proto.NodeID) { - defer rpcWG.Done() - resp := &MuxSignBillingResp{} - - if err := c.cl.CallNodeWithContext( - ctx, id, route.SQLCSignBilling.String(), req, resp, - ); err != nil { - log.WithFields(log.Fields{ - "peer": c.rt.getPeerInfoString(), - "time": c.rt.getChainTimeString(), - }).WithError(err).Error("failed to send sign billing request") - } - - respC <- &resp.SignBillingResp - }(s) - } - } -} - -// LaunchBilling launches a new billing process for the blocks within height range [low, high] -// (inclusive). -func (c *Chain) LaunchBilling(low, high int32) (err error) { - var ( - req *types.BillingRequest - ) - - defer log.WithFields(log.Fields{ - "peer": c.rt.getPeerInfoString(), - "time": c.rt.getChainTimeString(), - "low": low, - "high": high, - }).WithError(err).Debug("launched billing process") - - if req, err = c.getBilling(low, high); err != nil { - return - } - - if _, err = req.PackRequestHeader(); err != nil { - return - } - - c.rt.goFunc(func(ctx context.Context) { c.collectBillingSignatures(ctx, req) }) - return -} - -// SignBilling signs a billing request. -func (c *Chain) SignBilling(req *types.BillingRequest) ( - pub *asymmetric.PublicKey, sig *asymmetric.Signature, err error, -) { - var ( - loc *types.BillingRequest - ) - defer log.WithFields(log.Fields{ - "peer": c.rt.getPeerInfoString(), - "time": c.rt.getChainTimeString(), - "low": req.Header.LowHeight, - "high": req.Header.HighHeight, - }).WithError(err).Debug("processing sign billing request") - - // Verify billing results - if err = req.VerifySignatures(); err != nil { - return - } - if loc, err = c.getBilling(req.Header.LowHeight, req.Header.HighHeight); err != nil { - return - } - if err = req.Compare(loc); err != nil { - return - } - pub, sig, err = req.SignRequestHeader(c.pk, false) - return -} - // AddSubscription is used by dbms to add an observer. func (c *Chain) AddSubscription(nodeID proto.NodeID, startHeight int32) (err error) { // send previous height and transactions using AdviseAckedQuery/AdviseNewBlock RPC method diff --git a/sqlchain/errors.go b/sqlchain/errors.go index 7ed223777..bdb3c1a0f 100644 --- a/sqlchain/errors.go +++ b/sqlchain/errors.go @@ -21,85 +21,25 @@ import ( ) var ( - // ErrFieldConversion indicates an incompatible field conversion during data unmarshalling from - // a protobuf message, such as converting a non-digital string to a BigInt. - ErrFieldConversion = errors.New("incompatible field type conversion") - - // ErrFieldLength indicates an unexpected array field length during data unmarshalling from a - // protobuf message. Since protobuf doesn't have fixed size array, we need to check the slice - // length before read it back from a slice field to a fixed size array field. - ErrFieldLength = errors.New("unexpected slice field length") - - // ErrNilValue indicates that an unexpected but not fatal nil value is detected , hence return - // it as an error. - ErrNilValue = errors.New("unexpected nil value") - // ErrParentNotFound indicates an error failing to find parent node during a chain reloading. ErrParentNotFound = errors.New("could not find parent node") - - // ErrBlockExists indicates that a received block is already in the indexed. - ErrBlockExists = errors.New("block already exists") - // ErrInvalidBlock indicates an invalid block which does not extend the best chain while // pushing new blocks. ErrInvalidBlock = errors.New("invalid block") - - // ErrBlockTimestampOutOfPeriod indicates a block producing timestamp verification failure. - ErrBlockTimestampOutOfPeriod = errors.New("block timestamp is out of producing period") - - // ErrMultipleAckOfResponse indicates that multiple acknowledgements for a same query response - // is detected. - ErrMultipleAckOfResponse = errors.New("multiple acknowledgements of same response") - // ErrMultipleAckOfSeqNo indicates that multiple acknowledgements for a same sequence number is // detected. ErrMultipleAckOfSeqNo = errors.New("multiple acknowledgements of same sequence number") - - // ErrQueryExpired indicates that a received query Response/Ack has expired. - ErrQueryExpired = errors.New("query has expired") - - // ErrQueryNotCached indicates that a wanted query is not cached locally. - ErrQueryNotCached = errors.New("query is not cached locally") - - // ErrQuerySignedByAnotherBlock indicates that a query is already signed in a known block - // during the verification of a new introduced block. - ErrQuerySignedByAnotherBlock = errors.New("query has been packed by another block") - - // ErrCorruptedIndex indicates that a corrupted index item is detected. - ErrCorruptedIndex = errors.New("corrupted index item") - // ErrUnknownMuxRequest indicates that the multiplexing request endpoint is not found. ErrUnknownMuxRequest = errors.New("unknown multiplexing request") - + // ErrQueryExpired indicates that a received query Response/Ack has expired. + ErrQueryExpired = errors.New("query has expired") // ErrUnknownProducer indicates that the block has an unknown producer. ErrUnknownProducer = errors.New("unknown block producer") - // ErrInvalidProducer indicates that the block has an invalid producer. ErrInvalidProducer = errors.New("invalid block producer") - - // ErrUnavailableBillingRang indicates that the billing range is not available now. - ErrUnavailableBillingRang = errors.New("unavailable billing range") - - // ErrHashNotMatch indicates that a message hash value doesn't match the original hash value - // given in its hash field. - ErrHashNotMatch = errors.New("hash value doesn't match") - - // ErrMetaStateNotFound indicates that meta state not found in db. - ErrMetaStateNotFound = errors.New("meta state not found in db") - - // ErrAckQueryNotFound indicates that an acknowledged query record is not found. - ErrAckQueryNotFound = errors.New("acknowledged query not found") - // ErrQueryNotFound indicates that a query is not found in the index. ErrQueryNotFound = errors.New("query not found") - - // ErrInvalidRequest indicates the query is invalid. - ErrInvalidRequest = errors.New("invalid request") - // ErrResponseSeqNotMatch indicates that a response sequence id doesn't match the original one // in the index. ErrResponseSeqNotMatch = errors.New("response sequence id doesn't match") - - // ErrInvalidTransactionType indicates that the transaction type is invalid. - ErrInvalidTransactionType = errors.New("invalid transaction type") ) diff --git a/sqlchain/mux.go b/sqlchain/mux.go index 7dea6dfea..836f038c9 100644 --- a/sqlchain/mux.go +++ b/sqlchain/mux.go @@ -103,34 +103,6 @@ type MuxFetchBlockResp struct { FetchBlockResp } -// MuxSignBillingReq defines a request of the SignBilling RPC method. -type MuxSignBillingReq struct { - proto.Envelope - proto.DatabaseID - SignBillingReq -} - -// MuxSignBillingResp defines a response of the SignBilling RPC method. -type MuxSignBillingResp struct { - proto.Envelope - proto.DatabaseID - SignBillingResp -} - -// MuxLaunchBillingReq defines a request of the LaunchBilling RPC method. -type MuxLaunchBillingReq struct { - proto.Envelope - proto.DatabaseID - LaunchBillingReq -} - -// MuxLaunchBillingResp defines a response of the LaunchBilling RPC method. -type MuxLaunchBillingResp struct { - proto.Envelope - proto.DatabaseID - LaunchBillingResp -} - // MuxSubscribeTransactionsReq defines a request of the SubscribeTransactions RPC method. type MuxSubscribeTransactionsReq struct { proto.Envelope @@ -205,30 +177,6 @@ func (s *MuxService) FetchBlock(req *MuxFetchBlockReq, resp *MuxFetchBlockResp) return ErrUnknownMuxRequest } -// SignBilling is the RPC method to get signature for a billing request from the target server. -func (s *MuxService) SignBilling(req *MuxSignBillingReq, resp *MuxSignBillingResp) (err error) { - if v, ok := s.serviceMap.Load(req.DatabaseID); ok { - resp.Envelope = req.Envelope - resp.DatabaseID = req.DatabaseID - return v.(*ChainRPCService).SignBilling(&req.SignBillingReq, &resp.SignBillingResp) - } - - return ErrUnknownMuxRequest -} - -// LaunchBilling is the RPC method to launch a new billing process in the target server. -func (s *MuxService) LaunchBilling(req *MuxLaunchBillingReq, resp *MuxLaunchBillingResp) ( - err error, -) { - if v, ok := s.serviceMap.Load(req.DatabaseID); ok { - resp.Envelope = req.Envelope - resp.DatabaseID = req.DatabaseID - return v.(*ChainRPCService).LaunchBilling(&req.LaunchBillingReq, &resp.LaunchBillingResp) - } - - return ErrUnknownMuxRequest -} - // SubscribeTransactions is the RPC method to subscribe transactions from the target server. func (s *MuxService) SubscribeTransactions(req *MuxSubscribeTransactionsReq, resp *MuxSubscribeTransactionsResp) (err error) { if v, ok := s.serviceMap.Load(req.DatabaseID); ok { diff --git a/sqlchain/rpc.go b/sqlchain/rpc.go index e9e8ff217..e9691d668 100644 --- a/sqlchain/rpc.go +++ b/sqlchain/rpc.go @@ -17,8 +17,6 @@ package sqlchain import ( - "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" - "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/types" ) @@ -66,27 +64,6 @@ type FetchBlockResp struct { Block *types.Block } -// SignBillingReq defines a request of the SignBilling RPC method. -type SignBillingReq struct { - types.BillingRequest -} - -// SignBillingResp defines a response of the SignBilling RPC method. -type SignBillingResp struct { - HeaderHash hash.Hash - Signee *asymmetric.PublicKey - Signature *asymmetric.Signature -} - -// LaunchBillingReq defines a request of LaunchBilling RPC method. -type LaunchBillingReq struct { - Low, High int32 -} - -// LaunchBillingResp defines a response of LaunchBilling RPC method. -type LaunchBillingResp struct { -} - // SubscribeTransactionsReq defines a request of SubscribeTransaction RPC method. type SubscribeTransactionsReq struct { SubscriberID proto.NodeID @@ -131,18 +108,6 @@ func (s *ChainRPCService) FetchBlock(req *FetchBlockReq, resp *FetchBlockResp) ( return } -// SignBilling is the RPC method to get signature for a billing request from the target server. -func (s *ChainRPCService) SignBilling(req *SignBillingReq, resp *SignBillingResp) (err error) { - resp.HeaderHash = req.BillingRequest.RequestHash - resp.Signee, resp.Signature, err = s.chain.SignBilling(&req.BillingRequest) - return -} - -// LaunchBilling is the RPC method to launch a new billing process in the target server. -func (s *ChainRPCService) LaunchBilling(req *LaunchBillingReq, _ *LaunchBillingResp) error { - return s.chain.LaunchBilling(req.Low, req.High) -} - // SubscribeTransactions is the RPC method to fetch subscribe new packed and confirmed transactions from the target server. func (s *ChainRPCService) SubscribeTransactions(req *SubscribeTransactionsReq, _ *SubscribeTransactionsResp) error { return s.chain.AddSubscription(req.SubscriberID, req.Height) diff --git a/sqlchain/runtime.go b/sqlchain/runtime.go index 8c1800982..88c680d7e 100644 --- a/sqlchain/runtime.go +++ b/sqlchain/runtime.go @@ -51,10 +51,6 @@ type runtime struct { blockCacheTTL int32 // muxServer is the multiplexing service of sql-chain PRC. muxService *MuxService - // price sets query price in gases. - price map[types.QueryType]uint64 - producingReward uint64 - billingPeriods int32 // peersMutex protects following peers-relative fields. peersMutex sync.Mutex @@ -104,16 +100,13 @@ func newRunTime(ctx context.Context, c *Config) (r *runtime) { ctx: cld, cancel: ccl, - period: c.Period, - tick: c.Tick, - queryTTL: c.QueryTTL, - blockCacheTTL: blockCacheTTLRequired(c), - muxService: c.MuxService, - price: c.Price, - producingReward: c.ProducingReward, - billingPeriods: c.BillingPeriods, - peers: c.Peers, - server: c.Server, + period: c.Period, + tick: c.Tick, + queryTTL: c.QueryTTL, + blockCacheTTL: blockCacheTTLRequired(c), + muxService: c.MuxService, + peers: c.Peers, + server: c.Server, index: func() int32 { if index, found := c.Peers.Find(c.Server); found { return index @@ -206,11 +199,6 @@ func (r *runtime) setNextTurn() { r.nextTurn++ } -// getQueryGas gets the consumption of gas for a specified query type. -func (r *runtime) getQueryGas(t types.QueryType) uint64 { - return r.price[t] -} - // stop sends a signal to the Runtime stop channel by closing it. func (r *runtime) stop(dbID proto.DatabaseID) { r.stopService(dbID) diff --git a/sqlchain/xxx_test.go b/sqlchain/xxx_test.go index 3e45a73b3..80b5719cb 100644 --- a/sqlchain/xxx_test.go +++ b/sqlchain/xxx_test.go @@ -72,18 +72,6 @@ func newRandomNode() (node *nodeProfile, err error) { return } -func newRandomNodes(n int) (nodes []*nodeProfile, err error) { - nodes = make([]*nodeProfile, n) - - for i := range nodes { - if nodes[i], err = newRandomNode(); err != nil { - return - } - } - - return -} - func createRandomString(offset, length int, s *string) { buff := make([]byte, rand.Intn(length)+offset) rand.Read(buff) @@ -186,40 +174,6 @@ func createRandomQueryResponse(cli, worker *nodeProfile) ( return } -func createRandomQueryResponseWithRequest(req *types.SignedRequestHeader, worker *nodeProfile) ( - r *types.SignedResponseHeader, err error, -) { - resp := &types.Response{ - Header: types.SignedResponseHeader{ - ResponseHeader: types.ResponseHeader{ - Request: *req, - NodeID: worker.NodeID, - Timestamp: createRandomTimeAfter(req.Timestamp, 100), - }, - }, - Payload: types.ResponsePayload{ - Columns: createRandomStrings(10, 10, 10, 10), - DeclTypes: createRandomStrings(10, 10, 10, 10), - Rows: make([]types.ResponseRow, rand.Intn(10)+10), - }, - } - - for i := range resp.Payload.Rows { - s := createRandomStrings(10, 10, 10, 10) - resp.Payload.Rows[i].Values = make([]interface{}, len(s)) - for j := range resp.Payload.Rows[i].Values { - resp.Payload.Rows[i].Values[j] = s[j] - } - } - - if err = resp.Sign(worker.PrivateKey); err != nil { - return - } - - r = &resp.Header - return -} - func createRandomQueryAckWithResponse(resp *types.SignedResponseHeader, cli *nodeProfile) ( r *types.SignedAckHeader, err error, ) { @@ -241,47 +195,6 @@ func createRandomQueryAckWithResponse(resp *types.SignedResponseHeader, cli *nod return } -func createRandomQueryAck(cli, worker *nodeProfile) (r *types.SignedAckHeader, err error) { - resp, err := createRandomQueryResponse(cli, worker) - - if err != nil { - return - } - - ack := &types.Ack{ - Header: types.SignedAckHeader{ - AckHeader: types.AckHeader{ - Response: *resp, - NodeID: cli.NodeID, - Timestamp: createRandomTimeAfter(resp.Timestamp, 100), - }, - }, - } - - if err = ack.Sign(cli.PrivateKey, true); err != nil { - return - } - - r = &ack.Header - return -} - -func createRandomNodesAndAck() (r *types.SignedAckHeader, err error) { - cli, err := newRandomNode() - - if err != nil { - return - } - - worker, err := newRandomNode() - - if err != nil { - return - } - - return createRandomQueryAck(cli, worker) -} - func registerNodesWithPublicKey(pub *asymmetric.PublicKey, diff int, num int) ( nis []cpuminer.NonceInfo, err error) { nis = make([]cpuminer.NonceInfo, num) @@ -372,48 +285,6 @@ func createRandomBlock(parent hash.Hash, isGenesis bool) (b *types.Block, err er return } -func createRandomQueries(x int) (acks []*types.SignedAckHeader, err error) { - n := rand.Intn(x) - acks = make([]*types.SignedAckHeader, n) - - for i := range acks { - if acks[i], err = createRandomNodesAndAck(); err != nil { - return - } - } - - return -} - -func createRandomBlockWithQueries(genesis, parent hash.Hash, acks []*types.SignedAckHeader) ( - b *types.Block, err error, -) { - // Generate key pair - priv, _, err := asymmetric.GenSecp256k1KeyPair() - - if err != nil { - return - } - - h := hash.Hash{} - rand.Read(h[:]) - - b = &types.Block{ - SignedHeader: types.SignedHeader{ - Header: types.Header{ - Version: 0x01000000, - Producer: proto.NodeID(h.String()), - GenesisHash: genesis, - ParentHash: parent, - Timestamp: time.Now().UTC(), - }, - }, - } - - err = b.PackAndSignBlock(priv) - return -} - func createTestPeers(num int) (nis []cpuminer.NonceInfo, p *proto.Peers, err error) { if num <= 0 { return diff --git a/storage/storage.go b/storage/storage.go index 7e36bad0e..e059819af 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -26,6 +26,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/twopc" "github.com/CovenantSQL/CovenantSQL/utils/log" + // Register CovenantSQL/go-sqlite3-encrypt engine. _ "github.com/CovenantSQL/go-sqlite3-encrypt" ) diff --git a/test/GNTE/conf/node_0/config.yaml b/test/GNTE/conf/node_0/config.yaml index 530fb29c5..be7ed85bd 100644 --- a/test/GNTE/conf/node_0/config.yaml +++ b/test/GNTE/conf/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.1.2:4661" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -42,6 +43,34 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_1/config.yaml b/test/GNTE/conf/node_1/config.yaml index 5074978d1..69ddcc69c 100644 --- a/test/GNTE/conf/node_1/config.yaml +++ b/test/GNTE/conf/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.1.3:4661" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -42,6 +43,34 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_2/config.yaml b/test/GNTE/conf/node_2/config.yaml index 4663b6cd9..3acffc6fa 100644 --- a/test/GNTE/conf/node_2/config.yaml +++ b/test/GNTE/conf/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.1.4:4661" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -42,6 +43,34 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_c/config.yaml b/test/GNTE/conf/node_c/config.yaml index ea1eb111d..fa2c62bb2 100644 --- a/test/GNTE/conf/node_c/config.yaml +++ b/test/GNTE/conf/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.0.254:4661" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/GNTE/conf/node_miner_10.250.100.2/config.yaml b/test/GNTE/conf/node_miner_10.250.100.2/config.yaml index a11649d39..c9502ed53 100644 --- a/test/GNTE/conf/node_miner_10.250.100.2/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.2:4661" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.3/config.yaml b/test/GNTE/conf/node_miner_10.250.100.3/config.yaml index 8096dab25..2e49c3115 100644 --- a/test/GNTE/conf/node_miner_10.250.100.3/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.3/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.3:4661" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.4/config.yaml b/test/GNTE/conf/node_miner_10.250.100.4/config.yaml index b420ac11b..403b7b9b2 100644 --- a/test/GNTE/conf/node_miner_10.250.100.4/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.4/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.4:4661" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.5/config.yaml b/test/GNTE/conf/node_miner_10.250.100.5/config.yaml index f20d7ee53..490caa74b 100755 --- a/test/GNTE/conf/node_miner_10.250.100.5/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.5/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.5:4661" ThisNodeID: "00eda359cd2aa0920cdd37b083b896cb18cd26b3bd51744d1b4f127830f820f2" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.6/config.yaml b/test/GNTE/conf/node_miner_10.250.100.6/config.yaml index f5fc6a3ad..24ff73a55 100755 --- a/test/GNTE/conf/node_miner_10.250.100.6/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.6/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.6:4661" ThisNodeID: "0017017845ff9f9f7e8599d308652eb8ce480e689fbd49afb6b44cc9726cf84b" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.7/config.yaml b/test/GNTE/conf/node_miner_10.250.100.7/config.yaml index ea248251f..a7a2abc68 100755 --- a/test/GNTE/conf/node_miner_10.250.100.7/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.7/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.7:4661" ThisNodeID: "0075b97519d0a5cf9f7269a61b82bb3e082a5e7d796604e877ee28d08491979a" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.8/config.yaml b/test/GNTE/conf/node_miner_10.250.100.8/config.yaml index e38b3dd3a..1b9c4859e 100755 --- a/test/GNTE/conf/node_miner_10.250.100.8/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.8/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.8:4661" ThisNodeID: "0060bb3394f5185f760af690b0c124a70acbaf952fd79d794a0d394c37d7c0bc" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/conf/node_miner_10.250.100.9/config.yaml b/test/GNTE/conf/node_miner_10.250.100.9/config.yaml index 6969421de..5e9c09e59 100755 --- a/test/GNTE/conf/node_miner_10.250.100.9/config.yaml +++ b/test/GNTE/conf/node_miner_10.250.100.9/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "10.250.100.9:4661" ThisNodeID: "004e5cf49e88f6e35e344f35d73ffe6232d4ebe93a63a825e171b8f6f2a88859" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -33,11 +34,39 @@ BlockProducer: MerkleRoot: 0000000000000000000000000000000000000000000000000000000000000001 ParentHash: 0000000000000000000000000000000000000000000000000000000000000001 Timestamp: 2018-08-13T21:59:59.12Z + BaseAccounts: + - Address: ba0ba731c7a76ccef2c1170f42038f7e228dfb474ef0190dfe35d9a37911ed37 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 1a7b0959bbd0d0ec529278a61c0056c277bffe75b2646e1699b46b10a90210be + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9235bc4130a2ed4e6c35ea189dab35198ebb105640bedb97dd5269cc80863b16 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 9e1618775cceeb19f110e04fbc6c5bca6c8e4e9b116e193a42fe69bf602e7bcd + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: ae93d3414f68943ea4daf76155eaee438f2b9600db588202c85853b03a01515c + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: d1797377721629ca5426cd014bdbf245342efb2d612243561c6f11957dda4600 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: 2544d68886b2d0c3276d1ea6f8735ba7e25952163a13c1b9a485bebf7ad8e635 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: e9908011ffbcd4afbad8d503174056d2dbe8536f58b41dd300835bdd52ec35b8 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 + - Address: f09a1dba38c187a3cf433ec86c74878cb6dc97af5c91de0bbcadc3ccd47f0df7 + StableCoinBalance: 10000000000000000000 + CovenantCoinBalance: 10000000000000000000 Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "60s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/GNTE/run.sh b/test/GNTE/run.sh index 3afb4739d..2d6be6b36 100755 --- a/test/GNTE/run.sh +++ b/test/GNTE/run.sh @@ -11,7 +11,8 @@ echo ${PROJECT_DIR} # Build #Notice!!!!: uncomment this when you run this manually. -#cd ${PROJECT_DIR} && ./build.sh +#cd ${PROJECT_DIR} && make clean +#cd ${PROJECT_DIR} && make use_all_cores BENCHRESULT_FILE=${PROJECT_DIR}/bench.txt if [ -f ${BENCHRESULT_FILE} ];then @@ -23,7 +24,7 @@ if [ -f ${tmp_file} ];then fi # Clean submodule -cd ${TEST_WD}/GNTE/ && git clean -dfx +cd ${TEST_WD}/GNTE/ && sudo git clean -dfx for gnte_yaml in ${yaml[@]}; do @@ -38,7 +39,7 @@ do cd ${TEST_WD}/GNTE && bash -x ./build.sh # Clean - cd ${TEST_WD} && bash ./GNTE/scripts/cleanupDB.sh + cd ${TEST_WD} && sudo ./GNTE/scripts/cleanupDB.sh cd ${TEST_WD}/GNTE && bash -x ./generate.sh ${gnte_yaml} # Bench GNTE @@ -50,7 +51,7 @@ do done # clean GNTE docker -cd ${TEST_WD} && bash ./GNTE/scripts/cleanupDB.sh +cd ${TEST_WD} && sudo ./GNTE/scripts/cleanupDB.sh cd ${TEST_WD} && bash ./GNTE/scripts/clean.sh perl -lane 'print $F[0], "\t", $F[1], "\t", $F[2], "\t", 1000000000.0/$F[2] if $F[2]; print if /script/' ${tmp_file} > ${BENCHRESULT_FILE} diff --git a/test/bootstrap.yaml b/test/bootstrap.yaml index 75136c07d..671ed9f42 100644 --- a/test/bootstrap.yaml +++ b/test/bootstrap.yaml @@ -7,6 +7,7 @@ ListenAddr: "127.0.0.1:2120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 Period: 3600 +ChainBusPeriod: 20s MinProviderDeposit: 1000000 ValidDNSKeys: koPbw9wmYZ7ggcjnQ6ayHyhHaDNMYELKTqT+qRGrZpWSccr/lBcrm10Z1PuQHB3Azhii+sb0PYFkH1ruxLhe5g==: cloudflare.com diff --git a/test/fuse/node_0/config.yaml b/test/fuse/node_0/config.yaml index 429d71f10..d45165d29 100644 --- a/test/fuse/node_0/config.yaml +++ b/test/fuse/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:6122" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/fuse/node_1/config.yaml b/test/fuse/node_1/config.yaml index 2a28b0860..6e97c1945 100644 --- a/test/fuse/node_1/config.yaml +++ b/test/fuse/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:6121" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/fuse/node_2/config.yaml b/test/fuse/node_2/config.yaml index fa92df2b6..e714897cb 100644 --- a/test/fuse/node_2/config.yaml +++ b/test/fuse/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:6120" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/fuse/node_c/config.yaml b/test/fuse/node_c/config.yaml index 8fbce2852..7fb50336e 100644 --- a/test/fuse/node_c/config.yaml +++ b/test/fuse/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:6120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/fuse/node_miner_0/config.yaml b/test/fuse/node_miner_0/config.yaml index 2e30e01bc..81ec69cfe 100644 --- a/test/fuse/node_miner_0/config.yaml +++ b/test/fuse/node_miner_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3144" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/fuse/node_miner_1/config.yaml b/test/fuse/node_miner_1/config.yaml index 639638c2d..84eefab7d 100644 --- a/test/fuse/node_miner_1/config.yaml +++ b/test/fuse/node_miner_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3145" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/fuse/node_miner_2/config.yaml b/test/fuse/node_miner_2/config.yaml index f44645a7a..34d8fd5ad 100644 --- a/test/fuse/node_miner_2/config.yaml +++ b/test/fuse/node_miner_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3146" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/integration/node_0/config.yaml b/test/integration/node_0/config.yaml index 7b26669ba..397b65eb8 100644 --- a/test/integration/node_0/config.yaml +++ b/test/integration/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3122" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/integration/node_1/config.yaml b/test/integration/node_1/config.yaml index f054587c9..d35061395 100644 --- a/test/integration/node_1/config.yaml +++ b/test/integration/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3121" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/integration/node_2/config.yaml b/test/integration/node_2/config.yaml index 0c5e2ecfa..85dce477d 100644 --- a/test/integration/node_2/config.yaml +++ b/test/integration/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3120" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/integration/node_c/config.yaml b/test/integration/node_c/config.yaml index 1f90e0aca..f4f265e8c 100644 --- a/test/integration/node_c/config.yaml +++ b/test/integration/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:3120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/integration/node_miner_0/config.yaml b/test/integration/node_miner_0/config.yaml index e157a3150..8016896ab 100644 --- a/test/integration/node_miner_0/config.yaml +++ b/test/integration/node_miner_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2144" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "60s" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/integration/node_miner_1/config.yaml b/test/integration/node_miner_1/config.yaml index d18225403..f4b53d9cb 100644 --- a/test/integration/node_miner_1/config.yaml +++ b/test/integration/node_miner_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2145" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "60s" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/integration/node_miner_2/config.yaml b/test/integration/node_miner_2/config.yaml index b2281fa63..aafdfefc9 100644 --- a/test/integration/node_miner_2/config.yaml +++ b/test/integration/node_miner_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2146" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 2 +BillingBlockCount: 2 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "60s" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/leak/client.yaml b/test/leak/client.yaml index d9025a97d..77bee3fca 100644 --- a/test/leak/client.yaml +++ b/test/leak/client.yaml @@ -6,6 +6,7 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 +ChainBusPeriod: 1s Period: 3600 MinProviderDeposit: 1000000 ValidDNSKeys: diff --git a/test/leak/leader.yaml b/test/leak/leader.yaml index c900a02b7..93ddef97b 100644 --- a/test/leak/leader.yaml +++ b/test/leak/leader.yaml @@ -6,7 +6,8 @@ DHTFileName: "./leader/dht.db" ListenAddr: "127.0.0.1:2331" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_0/config.yaml b/test/mainchain/node_0/config.yaml index 15a9e38b8..89803b202 100644 --- a/test/mainchain/node_0/config.yaml +++ b/test/mainchain/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5122" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_1/config.yaml b/test/mainchain/node_1/config.yaml index ac2d236d9..2c201b374 100644 --- a/test/mainchain/node_1/config.yaml +++ b/test/mainchain/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5121" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_2/config.yaml b/test/mainchain/node_2/config.yaml index 00aadfde2..3205f0ef9 100644 --- a/test/mainchain/node_2/config.yaml +++ b/test/mainchain/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5120" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_c/config.yaml b/test/mainchain/node_c/config.yaml index 14b72c863..2222031a6 100644 --- a/test/mainchain/node_c/config.yaml +++ b/test/mainchain/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_miner_0/config.yaml b/test/mainchain/node_miner_0/config.yaml index d7a472603..b5c5bf3a1 100644 --- a/test/mainchain/node_miner_0/config.yaml +++ b/test/mainchain/node_miner_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5144" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/mainchain/node_miner_1/config.yaml b/test/mainchain/node_miner_1/config.yaml index 072081777..e20ae69f1 100644 --- a/test/mainchain/node_miner_1/config.yaml +++ b/test/mainchain/node_miner_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5145" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/mainchain/node_miner_2/config.yaml b/test/mainchain/node_miner_2/config.yaml index 0a6439acf..ae0fbbb56 100644 --- a/test/mainchain/node_miner_2/config.yaml +++ b/test/mainchain/node_miner_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5146" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/mainchain/node_multi_0/config.yaml b/test/mainchain/node_multi_0/config.yaml index 40365d8b7..07201fb26 100644 --- a/test/mainchain/node_multi_0/config.yaml +++ b/test/mainchain/node_multi_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5230" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_multi_1/config.yaml b/test/mainchain/node_multi_1/config.yaml index 727d306b8..2e8d93c14 100644 --- a/test/mainchain/node_multi_1/config.yaml +++ b/test/mainchain/node_multi_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5231" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_multi_2/config.yaml b/test/mainchain/node_multi_2/config.yaml index a961653a8..2b0a330d3 100644 --- a/test/mainchain/node_multi_2/config.yaml +++ b/test/mainchain/node_multi_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5232" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/mainchain/node_standalone/config.yaml b/test/mainchain/node_standalone/config.yaml index 40365d8b7..07201fb26 100644 --- a/test/mainchain/node_standalone/config.yaml +++ b/test/mainchain/node_standalone/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:5230" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_0/config.yaml b/test/node_0/config.yaml index 41e7d2e50..52ce19b51 100644 --- a/test/node_0/config.yaml +++ b/test/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2122" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_1/config.yaml b/test/node_1/config.yaml index ec2e88d59..ba7293c50 100644 --- a/test/node_1/config.yaml +++ b/test/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2121" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_2/config.yaml b/test/node_2/config.yaml index 2685e8e50..d6d0ae221 100644 --- a/test/node_2/config.yaml +++ b/test/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2120" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_c/config.yaml b/test/node_c/config.yaml index cf0d7f5ff..d3ba2e5ee 100644 --- a/test/node_c/config.yaml +++ b/test/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_standalone/config.yaml b/test/node_standalone/config.yaml index 9de74309a..f7f6c3953 100644 --- a/test/node_standalone/config.yaml +++ b/test/node_standalone/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2230" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/node_standalone/config2.yaml b/test/node_standalone/config2.yaml index c816ce191..3aa13d4dd 100644 --- a/test/node_standalone/config2.yaml +++ b/test/node_standalone/config2.yaml @@ -6,6 +6,7 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:12230" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 +ChainBusPeriod: 1s Period: 3600 MinProviderDeposit: 1000000 ValidDNSKeys: diff --git a/test/observation/node_0/config.yaml b/test/observation/node_0/config.yaml index be6b7e62d..21ad53261 100644 --- a/test/observation/node_0/config.yaml +++ b/test/observation/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4122" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/observation/node_1/config.yaml b/test/observation/node_1/config.yaml index 18d6b3a15..2ade86811 100644 --- a/test/observation/node_1/config.yaml +++ b/test/observation/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4121" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/observation/node_2/config.yaml b/test/observation/node_2/config.yaml index 8bf41bedc..98f8b5bc0 100644 --- a/test/observation/node_2/config.yaml +++ b/test/observation/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4120" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/observation/node_c/config.yaml b/test/observation/node_c/config.yaml index 762384688..f864108f3 100644 --- a/test/observation/node_c/config.yaml +++ b/test/observation/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4120" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/observation/node_miner_0/config.yaml b/test/observation/node_miner_0/config.yaml index 79d4fc45c..40d8203f0 100644 --- a/test/observation/node_miner_0/config.yaml +++ b/test/observation/node_miner_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4144" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/observation/node_miner_1/config.yaml b/test/observation/node_miner_1/config.yaml index f0d0c820a..d9058479b 100644 --- a/test/observation/node_miner_1/config.yaml +++ b/test/observation/node_miner_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4145" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/observation/node_miner_2/config.yaml b/test/observation/node_miner_2/config.yaml index 842e1943e..536917088 100644 --- a/test/observation/node_miner_2/config.yaml +++ b/test/observation/node_miner_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4146" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -37,7 +38,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/observation/node_observer/config.yaml b/test/observation/node_observer/config.yaml index 07fe9ca02..fc516fca0 100644 --- a/test/observation/node_observer/config.yaml +++ b/test/observation/node_observer/config.yaml @@ -4,9 +4,10 @@ PubKeyStoreFile: "public.keystore" PrivateKeyFile: "private.key" DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4123" -ThisNodeID: "0000037c786c744967bf536e58d51f24c074f14f693b1daedef88bf9efb92349" +ThisNodeID: "0000002100a44923021af2c91822e47998b0842cd450774c020257304acdce0b" QPS: 1000 -BillingPeriod: 3600 +BillingBlockCount: 3600 +ChainBusPeriod: 1s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -70,14 +71,14 @@ KnownNodes: Addr: 127.0.0.1:4120 PublicKey: "02c76216704d797c64c58bc11519fb68582e8e63de7e5b3b2dbbbe8733efe5fd24" Role: Follower -- ID: 0000037c786c744967bf536e58d51f24c074f14f693b1daedef88bf9efb92349 +- ID: 0000002100a44923021af2c91822e47998b0842cd450774c020257304acdce0b Nonce: - a: 284065 + a: 819961 b: 0 c: 0 - d: 16140901067704965389 + d: 7322664668 Addr: 127.0.0.1:4123 - PublicKey: 0246e1c483ef7db956a8e2ca87032d35f5b01574abdc9d23f2a9d180b12868c379 + PublicKey: 02ec784ca599f21ef93fe7abdc68d78817ab6c9b31f2324d15ea174d9da498b4c4 Role: Client - ID: 000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade Nonce: diff --git a/test/observation/node_observer/private.key b/test/observation/node_observer/private.key index d85e25900..f563980c1 100644 Binary files a/test/observation/node_observer/private.key and b/test/observation/node_observer/private.key differ diff --git a/test/pool/client.yaml b/test/pool/client.yaml index d06068a0e..7bb71b3ee 100644 --- a/test/pool/client.yaml +++ b/test/pool/client.yaml @@ -6,6 +6,7 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2520" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 +ChainBusPeriod: 1s Period: 3600 MinProviderDeposit: 1000000 ValidDNSKeys: diff --git a/test/pool/leader.yaml b/test/pool/leader.yaml index d0432fc1d..17403f548 100644 --- a/test/pool/leader.yaml +++ b/test/pool/leader.yaml @@ -6,6 +6,7 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:2530" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 +ChainBusPeriod: 1s Period: 3600 MinProviderDeposit: 1000000 ValidDNSKeys: diff --git a/test/service/node_0/config.yaml b/test/service/node_0/config.yaml index ccc407e22..a990c8734 100644 --- a/test/service/node_0/config.yaml +++ b/test/service/node_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.2:4661" ThisNodeID: "00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9" QPS: 1000 -BillingPeriod: 60 +ChainBusPeriod: 20s +BillingBlockCount: 60 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_1/config.yaml b/test/service/node_1/config.yaml index 29574d2b3..029cce62a 100644 --- a/test/service/node_1/config.yaml +++ b/test/service/node_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.3:4661" ThisNodeID: "00000381d46fd6cf7742d7fb94e2422033af989c0e348b5781b3219599a3af35" QPS: 1000 -BillingPeriod: 60 +ChainBusPeriod: 20s +BillingBlockCount: 60 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_2/config.yaml b/test/service/node_2/config.yaml index 9e856b401..056e1ce3b 100644 --- a/test/service/node_2/config.yaml +++ b/test/service/node_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.4:4661" ThisNodeID: "000000172580063ded88e010556b0aca2851265be8845b1ef397e8fce6ab5582" QPS: 1000 -BillingPeriod: 60 +ChainBusPeriod: 20s +BillingBlockCount: 60 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_adapter/config.yaml b/test/service/node_adapter/config.yaml index 8218abf1b..7e281ee34 100644 --- a/test/service/node_adapter/config.yaml +++ b/test/service/node_adapter/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.4:4661" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 60 +ChainBusPeriod: 20s +BillingBlockCount: 60 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_c/config.yaml b/test/service/node_c/config.yaml index f105c137c..3e00d1d89 100644 --- a/test/service/node_c/config.yaml +++ b/test/service/node_c/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "127.0.0.1:4661" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 3600 +ChainBusPeriod: 20s +BillingBlockCount: 3600 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_miner_0/config.yaml b/test/service/node_miner_0/config.yaml index fdc8a5071..80ba27bf7 100644 --- a/test/service/node_miner_0/config.yaml +++ b/test/service/node_miner_0/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.5:4661" ThisNodeID: "000005aa62048f85da4ae9698ed59c14ec0d48a88a07c15a32265634e7e64ade" QPS: 1000 -BillingPeriod: 60 +ChainBusPeriod: 20s +BillingBlockCount: 60 BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/service/node_miner_1/config.yaml b/test/service/node_miner_1/config.yaml index 66ff28b03..927ecbe42 100644 --- a/test/service/node_miner_1/config.yaml +++ b/test/service/node_miner_1/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.6:4661" ThisNodeID: "000005f4f22c06f76c43c4f48d5a7ec1309cc94030cbf9ebae814172884ac8b5" QPS: 1000 -BillingPeriod: 60 +BillingBlockCount: 60 +ChainBusPeriod: 20s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/service/node_miner_2/config.yaml b/test/service/node_miner_2/config.yaml index 0de85ccca..1dd21fdf1 100644 --- a/test/service/node_miner_2/config.yaml +++ b/test/service/node_miner_2/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.7:4661" ThisNodeID: "000003f49592f83d0473bddb70d543f1096b4ffed5e5f942a3117e256b7052b8" QPS: 1000 -BillingPeriod: 60 +BillingBlockCount: 60 +ChainBusPeriod: 20s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s @@ -50,7 +51,7 @@ Miner: IsTestMode: true RootDir: "./data" MaxReqTimeGap: "2s" - MetricCollectInterval: "1h" + ProvideServiceInterval: "3s" KnownNodes: - ID: 00000bef611d346c0cbe1beaa76e7f0ed705a194fdf9ac3a248ec70e9c198bf9 Nonce: diff --git a/test/service/node_mysql_adapter/config.yaml b/test/service/node_mysql_adapter/config.yaml index 1c71fd496..205948d60 100644 --- a/test/service/node_mysql_adapter/config.yaml +++ b/test/service/node_mysql_adapter/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.4:4661" ThisNodeID: "00000f3b43288fe99831eb533ab77ec455d13e11fc38ec35a42d4edd17aa320d" QPS: 1000 -BillingPeriod: 60 +BillingBlockCount: 60 +ChainBusPeriod: 20s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/test/service/node_observer/config.yaml b/test/service/node_observer/config.yaml index 9bc7f7a43..1bb088ac8 100644 --- a/test/service/node_observer/config.yaml +++ b/test/service/node_observer/config.yaml @@ -6,7 +6,8 @@ DHTFileName: "dht.db" ListenAddr: "172.254.1.9:4661" ThisNodeID: "0000037c786c744967bf536e58d51f24c074f14f693b1daedef88bf9efb92349" QPS: 1000 -BillingPeriod: 60 +BillingBlockCount: 60 +ChainBusPeriod: 20s BPPeriod: 3s BPTick: 1s SQLChainPeriod: 3s diff --git a/twopc/twopc_test.go b/twopc/twopc_test.go index e8e26d5dd..fa0accf04 100644 --- a/twopc/twopc_test.go +++ b/twopc/twopc_test.go @@ -67,9 +67,6 @@ type RaftNodeRPCServer struct { type RaftNode struct { RaftNodeRPCServer - - conn *etls.CryptoConn - client *rpc.Client } type RaftWriteBatchReq struct { diff --git a/types/account.go b/types/account.go index 143a25d98..8f8b7295e 100644 --- a/types/account.go +++ b/types/account.go @@ -39,8 +39,8 @@ const ( type UserPermission int32 const ( - // UnknownPerm defines the initial permission. - UnknownPerm UserPermission = iota + // Void defines the initial permission. + Void UserPermission = iota // Admin defines the admin user permission. Admin // Write defines the writer user permission. @@ -66,6 +66,27 @@ func (up *UserPermission) CheckAdmin() bool { return *up == Admin } +// Valid returns true if the value is a meaning permission value. +func (up *UserPermission) Valid() bool { + return *up >= Admin && *up < NumberOfUserPermission +} + +// FromString converts string to UserPermission. +func (up *UserPermission) FromString(perm string) { + switch perm { + case "Admin": + *up = Admin + case "Write": + *up = Write + case "Read": + *up = Read + case "Void": + *up = Void + default: + *up = NumberOfUserPermission + } +} + // Status defines status of a SQLChain user/miner. type Status int32 @@ -89,6 +110,12 @@ func (s *Status) EnableQuery() bool { return *s >= Normal && *s <= Reminder } +// PermStat defines the permissions status structure. +type PermStat struct { + Permission UserPermission + Status Status +} + // SQLChainUser defines a SQLChain user. type SQLChainUser struct { Address proto.AccountAddress diff --git a/types/bprpc.go b/types/bprpc.go index 786996d60..ba788d744 100644 --- a/types/bprpc.go +++ b/types/bprpc.go @@ -142,28 +142,15 @@ type OrderTakerResp struct { databaseID proto.DatabaseID } -// QueryAccountStableBalanceReq defines a request of the QueryAccountStableBalance RPC method. -type QueryAccountStableBalanceReq struct { +// QueryAccountTokenBalanceReq defines a request of the QueryAccountTokenBalance RPC method. +type QueryAccountTokenBalanceReq struct { proto.Envelope - Addr proto.AccountAddress -} - -// QueryAccountStableBalanceResp defines a request of the QueryAccountStableBalance RPC method. -type QueryAccountStableBalanceResp struct { - proto.Envelope - Addr proto.AccountAddress - OK bool - Balance uint64 -} - -// QueryAccountCovenantBalanceReq defines a request of the QueryAccountCovenantBalance RPC method. -type QueryAccountCovenantBalanceReq struct { - proto.Envelope - Addr proto.AccountAddress + Addr proto.AccountAddress + TokenType TokenType } -// QueryAccountCovenantBalanceResp defines a request of the QueryAccountCovenantBalance RPC method. -type QueryAccountCovenantBalanceResp struct { +// QueryAccountTokenBalanceResp defines a request of the QueryAccountTokenBalance RPC method. +type QueryAccountTokenBalanceResp struct { proto.Envelope Addr proto.AccountAddress OK bool diff --git a/types/chainstate.go b/types/chainstate.go deleted file mode 100644 index 0d3a868c0..000000000 --- a/types/chainstate.go +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018 The CovenantSQL Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package types - -import ( - "github.com/CovenantSQL/CovenantSQL/proto" -) - -// PermStat defines the permissions status structure. -type PermStat struct { - Permission UserPermission - Status Status -} - -// UserState defines the user state structure. -type UserState struct { - State map[proto.AccountAddress]*PermStat -} - -// NewUserState returns new user state instance. -func NewUserState() *UserState { - return &UserState{ - State: make(map[proto.AccountAddress]*PermStat), - } -} - -// UpdatePermission sets account permission. -func (us *UserState) UpdatePermission(user proto.AccountAddress, perm UserPermission) { - if state, ok := us.State[user]; ok { - state.Permission = perm - } else { - us.State[user] = &PermStat{ - Permission: perm, - } - } -} - -// AddPermission updates account permission. -func (us *UserState) AddPermission(user proto.AccountAddress, perm UserPermission) { - us.UpdatePermission(user, perm) -} - -// UpdateStatus update account status. -func (us *UserState) UpdateStatus(user proto.AccountAddress, stat Status) { - if state, ok := us.State[user]; ok { - state.Status = stat - } else { - us.State[user] = &PermStat{ - Status: stat, - } - } -} - -// AddStatus is an alias for UpdateStatus. -func (us *UserState) AddStatus(user proto.AccountAddress, stat Status) { - us.UpdateStatus(user, stat) -} - -// GetPermission returns the account permission. -func (us *UserState) GetPermission(user proto.AccountAddress) (up UserPermission, ok bool) { - permstat, ok := us.State[user] - up = permstat.Permission - return -} - -// GetStatus returns the account status. -func (us *UserState) GetStatus(user proto.AccountAddress) (stat Status, ok bool) { - permstat, ok := us.State[user] - stat = permstat.Status - return -} diff --git a/types/errors.go b/types/errors.go index 882074aa9..86ea4154d 100644 --- a/types/errors.go +++ b/types/errors.go @@ -26,20 +26,10 @@ var ( // ErrNodePublicKeyNotMatch indicates that the public key given with a node does not match the // one in the key store. ErrNodePublicKeyNotMatch = errors.New("node publick key doesn't match") - // ErrSignRequest indicates a failed signature compute operation. - ErrSignRequest = errors.New("signature compute failed") // ErrSignVerification indicates a failed signature verification. ErrSignVerification = errors.New("signature verification failed") // ErrBillingNotMatch indicates that the billing request doesn't match the local result. ErrBillingNotMatch = errors.New("billing request doesn't match") // ErrHashVerification indicates a failed hash verification. ErrHashVerification = errors.New("hash verification failed") - // ErrNotExists defines errors on manipulating a non-exists database instance. - ErrNotExists = errors.New("database instance not exists") - // ErrNoSuchUser indicates that user do not exist. - ErrNoSuchUser = errors.New("user not exist") - // ErrOverflow indicates computing overflow. - ErrOverflow = errors.New("computing overflow") - // ErrInvalidHeight indicates that received height is smaller than current height. - ErrInvalidHeight = errors.New("received height is smaller than current height") ) diff --git a/types/init_service_type_gen.go b/types/init_service_type_gen.go index ae24575c7..b289ec50d 100644 --- a/types/init_service_type_gen.go +++ b/types/init_service_type_gen.go @@ -31,19 +31,8 @@ func (z *InitServiceResponse) MarshalHash() (o []byte, err error) { var b []byte o = hsp.Require(b, z.Msgsize()) // map header, size 1 - // map header, size 2 - // map header, size 1 - o = append(o, 0x81, 0x81, 0x82, 0x82, 0x81, 0x81) - o = hsp.AppendArrayHeader(o, uint32(len(z.Header.InitServiceResponseHeader.Instances))) - for za0001 := range z.Header.InitServiceResponseHeader.Instances { - if oTemp, err := z.Header.InitServiceResponseHeader.Instances[za0001].MarshalHash(); err != nil { - return nil, err - } else { - o = hsp.AppendBytes(o, oTemp) - } - } - o = append(o, 0x82) - if oTemp, err := z.Header.DefaultHashSignVerifierImpl.MarshalHash(); err != nil { + o = append(o, 0x81, 0x81) + if oTemp, err := z.Header.MarshalHash(); err != nil { return nil, err } else { o = hsp.AppendBytes(o, oTemp) @@ -53,11 +42,7 @@ func (z *InitServiceResponse) MarshalHash() (o []byte, err error) { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *InitServiceResponse) Msgsize() (s int) { - s = 1 + 7 + 1 + 26 + 1 + 10 + hsp.ArrayHeaderSize - for za0001 := range z.Header.InitServiceResponseHeader.Instances { - s += z.Header.InitServiceResponseHeader.Instances[za0001].Msgsize() - } - s += 28 + z.Header.DefaultHashSignVerifierImpl.Msgsize() + s = 1 + 7 + z.Header.Msgsize() return } diff --git a/types/request_type_gen.go b/types/request_type_gen.go index 7033d7aa6..709e66bb9 100644 --- a/types/request_type_gen.go +++ b/types/request_type_gen.go @@ -106,20 +106,10 @@ func (z *Request) MarshalHash() (o []byte, err error) { o = append(o, 0x83, 0x83, 0x81, 0x81) o = hsp.AppendArrayHeader(o, uint32(len(z.Payload.Queries))) for za0001 := range z.Payload.Queries { - // map header, size 2 - o = append(o, 0x82, 0x82) - o = hsp.AppendString(o, z.Payload.Queries[za0001].Pattern) - o = append(o, 0x82) - o = hsp.AppendArrayHeader(o, uint32(len(z.Payload.Queries[za0001].Args))) - for za0002 := range z.Payload.Queries[za0001].Args { - // map header, size 2 - o = append(o, 0x82, 0x82) - o = hsp.AppendString(o, z.Payload.Queries[za0001].Args[za0002].Name) - o = append(o, 0x82) - o, err = hsp.AppendIntf(o, z.Payload.Queries[za0001].Args[za0002].Value) - if err != nil { - return - } + if oTemp, err := z.Payload.Queries[za0001].MarshalHash(); err != nil { + return nil, err + } else { + o = hsp.AppendBytes(o, oTemp) } } // map header, size 2 @@ -148,10 +138,7 @@ func (z *Request) MarshalHash() (o []byte, err error) { func (z *Request) Msgsize() (s int) { s = 1 + 8 + 1 + 8 + hsp.ArrayHeaderSize for za0001 := range z.Payload.Queries { - s += 1 + 8 + hsp.StringPrefixSize + len(z.Payload.Queries[za0001].Pattern) + 5 + hsp.ArrayHeaderSize - for za0002 := range z.Payload.Queries[za0001].Args { - s += 1 + 5 + hsp.StringPrefixSize + len(z.Payload.Queries[za0001].Args[za0002].Name) + 6 + hsp.GuessSize(z.Payload.Queries[za0001].Args[za0002].Value) - } + s += z.Payload.Queries[za0001].Msgsize() } s += 7 + 1 + 14 + z.Header.RequestHeader.Msgsize() + 28 + z.Header.DefaultHashSignVerifierImpl.Msgsize() + 9 + z.Envelope.Msgsize() return diff --git a/types/xxx_test.go b/types/xxx_test.go index 7e5f92fd0..ab9d8f77f 100644 --- a/types/xxx_test.go +++ b/types/xxx_test.go @@ -43,82 +43,14 @@ const ( letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ) -func generateRandomSQLChainUser() *SQLChainUser { - return &SQLChainUser{ - Address: proto.AccountAddress(generateRandomHash()), - Permission: UserPermission(rand.Int31n(int32(NumberOfUserPermission))), - } - -} - -func generateRandomSQLChainUsers(n int) (users []*SQLChainUser) { - users = make([]*SQLChainUser, n) - for i := range users { - users[i] = generateRandomSQLChainUser() - - } - return - -} - -func generateRandomAccountAddresses(n int) (s []proto.AccountAddress) { - s = make([]proto.AccountAddress, n) - for i := range s { - s[i] = proto.AccountAddress(generateRandomHash()) - - } - return - -} - -func generateRandomProfile() *SQLChainProfile { - return &SQLChainProfile{ - ID: generateRandomDatabaseID(), - Owner: proto.AccountAddress(generateRandomHash()), - Users: generateRandomSQLChainUsers(rand.Intn(10) + 1), - } - -} - -func generateRandomAccount() *Account { - return &Account{ - Address: proto.AccountAddress(generateRandomHash()), - TokenBalance: [SupportTokenNumber]uint64{rand.Uint64(), rand.Uint64()}, - Rating: rand.Float64(), - } - -} - -func generateRandomBytes(n int32) []byte { - s := make([]byte, n) - for i := range s { - s[i] = byte(rand.Int31n(2)) - - } - return s - -} - func generateRandomHash() hash.Hash { h := hash.Hash{} rand.Read(h[:]) return h - } func generateRandomDatabaseID() proto.DatabaseID { return proto.DatabaseID(randStringBytes(uuidLen)) - -} - -func generateRandomDatabaseIDs(n int32) []proto.DatabaseID { - s := make([]proto.DatabaseID, n) - for i := range s { - s[i] = proto.DatabaseID(randStringBytes(uuidLen)) - - } - return s - } func randStringBytes(n int) string { @@ -128,7 +60,6 @@ func randStringBytes(n int) string { } return string(b) - } func generateRandomBlock(parent hash.Hash, isGenesis bool) (b *BPBlock, err error) { @@ -386,22 +317,6 @@ func setup() { log.SetLevel(log.DebugLevel) } -func createRandomString(offset, length int, s *string) { - buff := make([]byte, rand.Intn(length)+offset) - rand.Read(buff) - *s = string(buff) -} - -func createRandomStrings(offset, length, soffset, slength int) (s []string) { - s = make([]string, rand.Intn(length)+offset) - - for i := range s { - createRandomString(soffset, slength, &s[i]) - } - - return -} - func createRandomBlock(parent hash.Hash, isGenesis bool) (b *Block, err error) { // Generate key pair priv, pub, err := asymmetric.GenSecp256k1KeyPair() diff --git a/utils/big.go b/utils/big.go index 6568671f5..7c4556073 100644 --- a/utils/big.go +++ b/utils/big.go @@ -24,12 +24,9 @@ import ( // Various big integer limit values. var ( - tt255 = BigPow(2, 255) - tt256 = BigPow(2, 256) - tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1)) - tt63 = BigPow(2, 63) - MaxBig256 = new(big.Int).Set(tt256m1) - MaxBig63 = new(big.Int).Sub(tt63, big.NewInt(1)) + tt255 = BigPow(2, 255) + tt256 = BigPow(2, 256) + tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1)) ) const ( diff --git a/utils/errors.go b/utils/errors.go deleted file mode 100644 index 25a9a89d1..000000000 --- a/utils/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -import "errors" - -var ( - // ErrInvalidType defines invalid type. - ErrInvalidType = errors.New("invalid type") -) diff --git a/utils/exec.go b/utils/exec.go index c533cd3bc..0a4db3616 100644 --- a/utils/exec.go +++ b/utils/exec.go @@ -42,23 +42,6 @@ func GetProjectSrcDir() string { return FJ(filepath.Dir(testFile), "../") } -// Build runs build.sh -func Build() (err error) { - wd := GetProjectSrcDir() - err = os.Chdir(wd) - if err != nil { - log.WithError(err).Error("change working dir failed") - return - } - cmd := exec.Command("./build.sh") - output, err := cmd.CombinedOutput() - if err != nil { - log.WithError(err).Error("build failed") - } - log.Debugf("build output info: %#v", string(output)) - return -} - // RunCommand runs a command and capture its output to a log file, // if toStd is true also output to stdout and stderr func RunCommand(bin string, args []string, processName string, workingDir string, logDir string, toStd bool) (err error) { diff --git a/utils/exec_test.go b/utils/exec_test.go index f0e37b55e..f413bca64 100644 --- a/utils/exec_test.go +++ b/utils/exec_test.go @@ -31,13 +31,6 @@ var ( logDir = FJ(testWorkingDir, "./log/") ) -func TestBuild(t *testing.T) { - Convey("build", t, func() { - log.SetLevel(log.DebugLevel) - So(Build(), ShouldBeNil) - }) -} - func TestRunServer(t *testing.T) { Convey("build", t, func() { log.SetLevel(log.DebugLevel) diff --git a/utils/integer.go b/utils/integer.go index 9d52f69c4..ca52b8889 100644 --- a/utils/integer.go +++ b/utils/integer.go @@ -18,25 +18,10 @@ package utils import ( "fmt" + "math" "strconv" ) -// Integer limit values. -const ( - MaxInt8 = 1<<7 - 1 - MinInt8 = -1 << 7 - MaxInt16 = 1<<15 - 1 - MinInt16 = -1 << 15 - MaxInt32 = 1<<31 - 1 - MinInt32 = -1 << 31 - MaxInt64 = 1<<63 - 1 - MinInt64 = -1 << 63 - MaxUint8 = 1<<8 - 1 - MaxUint16 = 1<<16 - 1 - MaxUint32 = 1<<32 - 1 - MaxUint64 = 1<<64 - 1 -) - // HexOrDecimal64 marshals uint64 as hex or decimal. type HexOrDecimal64 uint64 @@ -87,7 +72,7 @@ func SafeSub(x, y uint64) (uint64, bool) { // SafeAdd returns the result and whether overflow occurred. func SafeAdd(x, y uint64) (uint64, bool) { - return x + y, y > MaxUint64-x + return x + y, y > math.MaxUint64-x } // SafeMul returns multiplication result and whether overflow occurred. @@ -95,5 +80,5 @@ func SafeMul(x, y uint64) (uint64, bool) { if x == 0 || y == 0 { return 0, false } - return x * y, y > MaxUint64/x + return x * y, y > math.MaxUint64/x } diff --git a/utils/integer_test.go b/utils/integer_test.go index c63772875..3391e29d4 100644 --- a/utils/integer_test.go +++ b/utils/integer_test.go @@ -17,6 +17,7 @@ package utils import ( + "math" "testing" ) @@ -36,8 +37,8 @@ func TestOverflow(t *testing.T) { op operation }{ // add operations - {MaxUint64, 1, true, add}, - {MaxUint64 - 1, 1, false, add}, + {math.MaxUint64, 1, true, add}, + {math.MaxUint64 - 1, 1, false, add}, // sub operations {0, 1, true, sub}, @@ -46,8 +47,8 @@ func TestOverflow(t *testing.T) { // mul operations {0, 0, false, mul}, {10, 10, false, mul}, - {MaxUint64, 2, true, mul}, - {MaxUint64, 1, false, mul}, + {math.MaxUint64, 2, true, mul}, + {math.MaxUint64, 1, false, mul}, } { var overflows bool switch test.op { diff --git a/utils/log/logwrapper.go b/utils/log/logwrapper.go index 684e04a8f..72c1a37cc 100644 --- a/utils/log/logwrapper.go +++ b/utils/log/logwrapper.go @@ -46,12 +46,17 @@ const ( DebugLevel ) -// PkgDebugLogFilter is the log filter -// if package name exists and log level is more verbose, the log will be dropped -var PkgDebugLogFilter = map[string]logrus.Level{ - "metric": InfoLevel, - "rpc": InfoLevel, -} +var ( + // PkgDebugLogFilter is the log filter + // if package name exists and log level is more verbose, the log will be dropped + PkgDebugLogFilter = map[string]logrus.Level{ + "metric": InfoLevel, + "rpc": InfoLevel, + } + // SimpleLog is the flag of simple log format + // "Y" for true, "N" for false. defined in `go build` + SimpleLog = "N" +) // Logger wraps logrus logger type. type Logger logrus.Logger @@ -74,6 +79,11 @@ func NewCallerHook(stackLevels []logrus.Level) *CallerHook { // StandardCallerHook is a convenience initializer for LogrusStackHook{} with // default args. func StandardCallerHook() *CallerHook { + // defined in `go build` + if SimpleLog == "Y" { + return NewCallerHook([]logrus.Level{}) + } + return NewCallerHook( []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel}, ) @@ -98,6 +108,10 @@ func (hook *CallerHook) Fire(entry *logrus.Entry) error { // Levels define hook applicable level. func (hook *CallerHook) Levels() []logrus.Level { + // defined in `go build` + if SimpleLog == "Y" { + return []logrus.Level{} + } return []logrus.Level{ logrus.PanicLevel, logrus.FatalLevel, diff --git a/worker/chainbusservice.go b/worker/chainbusservice.go index 1e93ead1f..5ac6aa11a 100644 --- a/worker/chainbusservice.go +++ b/worker/chainbusservice.go @@ -45,9 +45,10 @@ type BusService struct { checkInterval time.Duration localAddress proto.AccountAddress - lock sync.Mutex // a lock for the map + lock sync.RWMutex // a lock for the map blockCount uint32 sqlChainProfiles map[proto.DatabaseID]*types.SQLChainProfile + sqlChainState map[proto.DatabaseID](map[proto.AccountAddress]*types.PermStat) } // NewBusService creates a new chain bus instance. @@ -73,8 +74,8 @@ func NewBusService( // GetCurrentDBMapping returns current cached db mapping. func (bs *BusService) GetCurrentDBMapping() (dbMap map[proto.DatabaseID]*types.SQLChainProfile) { dbMap = make(map[proto.DatabaseID]*types.SQLChainProfile) - bs.lock.Lock() - defer bs.lock.Unlock() + bs.lock.RLock() + defer bs.lock.RUnlock() for k, v := range bs.sqlChainProfiles { dbMap[k] = v } @@ -84,12 +85,23 @@ func (bs *BusService) GetCurrentDBMapping() (dbMap map[proto.DatabaseID]*types.S func (bs *BusService) updateState(count uint32, profiles []*types.SQLChainProfile) { bs.lock.Lock() defer bs.lock.Unlock() - var rebuilt = make(map[proto.DatabaseID]*types.SQLChainProfile) + var ( + rebuilt = make(map[proto.DatabaseID]*types.SQLChainProfile) + sqlchainState = make(map[proto.DatabaseID](map[proto.AccountAddress]*types.PermStat)) + ) for _, v := range profiles { rebuilt[v.ID] = v + sqlchainState[v.ID] = make(map[proto.AccountAddress]*types.PermStat) + for _, user := range v.Users { + sqlchainState[v.ID][user.Address] = &types.PermStat{ + Permission: user.Permission, + Status: user.Status, + } + } } atomic.StoreUint32(&bs.blockCount, count) bs.sqlChainProfiles = rebuilt + bs.sqlChainState = sqlchainState } func (bs *BusService) subscribeBlock(ctx context.Context) { @@ -179,12 +191,25 @@ func (bs *BusService) requestLastBlock() ( // RequestSQLProfile get specified database profile. func (bs *BusService) RequestSQLProfile(dbID proto.DatabaseID) (p *types.SQLChainProfile, ok bool) { - bs.lock.Lock() - defer bs.lock.Unlock() + bs.lock.RLock() + defer bs.lock.RUnlock() p, ok = bs.sqlChainProfiles[dbID] return } +// RequestPermStat fetches permission state from bus service. +func (bs *BusService) RequestPermStat( + dbID proto.DatabaseID, user proto.AccountAddress) (permStat *types.PermStat, ok bool, +) { + bs.lock.RLock() + defer bs.lock.RUnlock() + userState, ok := bs.sqlChainState[dbID] + if ok { + permStat, ok = userState[user] + } + return +} + func (bs *BusService) requestBP(method string, request interface{}, response interface{}) (err error) { var bpNodeID proto.NodeID if bpNodeID, err = rpc.GetCurrentBP(); err != nil { diff --git a/worker/chainbusservice_test.go b/worker/chainbusservice_test.go index 952a60329..2429061e6 100644 --- a/worker/chainbusservice_test.go +++ b/worker/chainbusservice_test.go @@ -53,17 +53,18 @@ func TestNewBusService(t *testing.T) { privKey *asymmetric.PrivateKey pubKey *asymmetric.PublicKey addr proto.AccountAddress - testCheckInterval = 1 * time.Second + testCheckInterval = 30 * time.Second + count uint32 ) privKey, err = kms.GetLocalPrivateKey() So(err, ShouldBeNil) pubKey = privKey.PubKey() addr, err = crypto.PubKeyHash(pubKey) So(err, ShouldBeNil) - ctx, _ := context.WithCancel(context.Background()) + ctx, cancelFunc := context.WithCancel(context.Background()) + defer cancelFunc() bs := NewBusService(ctx, addr, testCheckInterval) topic := fmt.Sprintf("/%s/", testOddBlocks.Transactions[0].GetTransactionType().String()) - var count uint32 err = bs.Subscribe(topic, func(tx interfaces.Transaction, c uint32) { atomic.AddUint32(&count, 1) }) @@ -73,47 +74,52 @@ func TestNewBusService(t *testing.T) { bs.Start() - time.Sleep(2 * time.Second) + time.Sleep(4 * time.Second) c := atomic.LoadUint32(&bs.blockCount) if c%2 == 0 { - p, ok := bs.RequestSQLProfile(testEventID) - So(ok, ShouldBeTrue) - exist := false - for _, profile := range testEventProfiles { - if profile.ID == p.ID { - So(p, ShouldResemble, profile) - exist = true - } - } - So(exist, ShouldBeTrue) dbMap := bs.GetCurrentDBMapping() for _, profile := range testEventProfiles { - p, ok := dbMap[profile.ID] + // test RequestSQLProfile + p, ok := bs.RequestSQLProfile(profile.ID) + So(ok, ShouldBeTrue) + So(p, ShouldResemble, profile) + + // test GetCurrentDBMapping + p, ok = dbMap[profile.ID] So(ok, ShouldBeTrue) So(profile, ShouldResemble, p) + + // test RequestPermStat + permStat, ok := bs.RequestPermStat(profile.ID, testAddr) + So(ok, ShouldBeTrue) + So(permStat.Status, ShouldEqual, profile.Users[0].Status) + So(permStat.Permission, ShouldEqual, profile.Users[0].Permission) + permStat, ok = bs.RequestPermStat(profile.ID, testNotExistAddr) } - p, ok = bs.RequestSQLProfile(testOddID) + p, ok := bs.RequestSQLProfile(testNotExistID) So(ok, ShouldBeFalse) So(p, ShouldBeNil) } else { - p, ok := bs.RequestSQLProfile(testOddID) - So(ok, ShouldBeTrue) - exist := false - for _, profile := range testOddProfiles { - if profile.ID == p.ID { - So(p, ShouldResemble, profile) - exist = true - } - } - So(exist, ShouldBeTrue) dbMap := bs.GetCurrentDBMapping() for _, profile := range testOddProfiles { - p, ok := dbMap[profile.ID] + p, ok := bs.RequestSQLProfile(profile.ID) + So(ok, ShouldBeTrue) + So(p, ShouldResemble, profile) + + // test GetCurrentDBMapping + p, ok = dbMap[profile.ID] So(ok, ShouldBeTrue) So(profile, ShouldResemble, p) + + // test RequestPermStat + permStat, ok := bs.RequestPermStat(profile.ID, testAddr) + So(ok, ShouldBeTrue) + So(permStat.Status, ShouldEqual, profile.Users[0].Status) + So(permStat.Permission, ShouldEqual, profile.Users[0].Permission) + permStat, ok = bs.RequestPermStat(profile.ID, testNotExistAddr) } - p, ok = bs.RequestSQLProfile(testEventID) + p, ok := bs.RequestSQLProfile(testNotExistID) So(ok, ShouldBeFalse) So(p, ShouldBeNil) } diff --git a/worker/db.go b/worker/db.go index c09034080..5a2043eb1 100644 --- a/worker/db.go +++ b/worker/db.go @@ -142,7 +142,7 @@ func NewDatabase(cfg *DBConfig, peers *proto.Peers, Tick: conf.GConf.SQLChainTick, QueryTTL: conf.GConf.SQLChainTTL, - UpdatePeriod: cfg.UpdatePeriod, + UpdatePeriod: cfg.UpdateBlockCount, } if db.chain, err = sqlchain.NewChain(chainCfg); err != nil { return diff --git a/worker/db_config.go b/worker/db_config.go index 794391e9f..410503232 100644 --- a/worker/db_config.go +++ b/worker/db_config.go @@ -32,7 +32,7 @@ type DBConfig struct { MaxWriteTimeGap time.Duration EncryptionKey string SpaceLimit uint64 - UpdatePeriod uint64 + UpdateBlockCount uint64 UseEventualConsistency bool ConsistencyLevel float64 SlowQueryTime time.Duration diff --git a/worker/db_test.go b/worker/db_test.go index bc872d172..aac4ea475 100644 --- a/worker/db_test.go +++ b/worker/db_test.go @@ -79,12 +79,12 @@ func TestSingleDatabase(t *testing.T) { // create file cfg := &DBConfig{ - DatabaseID: "TEST", - DataDir: rootDir, - KayakMux: kayakMuxService, - ChainMux: chainMuxService, - MaxWriteTimeGap: time.Second * 5, - UpdatePeriod: 2, + DatabaseID: "TEST", + DataDir: rootDir, + KayakMux: kayakMuxService, + ChainMux: chainMuxService, + MaxWriteTimeGap: time.Second * 5, + UpdateBlockCount: 2, } // create genesis block @@ -441,12 +441,12 @@ func TestInitFailed(t *testing.T) { // create file cfg := &DBConfig{ - DatabaseID: "TEST", - DataDir: rootDir, - KayakMux: kayakMuxService, - ChainMux: chainMuxService, - MaxWriteTimeGap: time.Duration(5 * time.Second), - UpdatePeriod: 2, + DatabaseID: "TEST", + DataDir: rootDir, + KayakMux: kayakMuxService, + ChainMux: chainMuxService, + MaxWriteTimeGap: time.Duration(5 * time.Second), + UpdateBlockCount: 2, } // create genesis block @@ -495,12 +495,12 @@ func TestDatabaseRecycle(t *testing.T) { // create file cfg := &DBConfig{ - DatabaseID: "TEST", - DataDir: rootDir, - KayakMux: kayakMuxService, - ChainMux: chainMuxService, - MaxWriteTimeGap: time.Duration(5 * time.Second), - UpdatePeriod: 2, + DatabaseID: "TEST", + DataDir: rootDir, + KayakMux: kayakMuxService, + ChainMux: chainMuxService, + MaxWriteTimeGap: time.Duration(5 * time.Second), + UpdateBlockCount: 2, } // create genesis block diff --git a/worker/dbms.go b/worker/dbms.go index e1c2a1e20..9329ea6d1 100644 --- a/worker/dbms.go +++ b/worker/dbms.go @@ -46,9 +46,6 @@ const ( // DBMetaFileName defines dbms meta file name. DBMetaFileName = "db.meta" - // CheckInterval defines the bus service period. - CheckInterval = time.Second - // DefaultSlowQueryTime defines the default slow query log time DefaultSlowQueryTime = time.Second * 5 ) @@ -57,7 +54,6 @@ const ( type DBMS struct { cfg *DBMSConfig dbMap sync.Map - chainMap sync.Map kayakMux *DBKayakMuxService chainMux *sqlchain.MuxService rpc *DBMSRPCService @@ -101,7 +97,7 @@ func NewDBMS(cfg *DBMSConfig) (dbms *DBMS, err error) { // init chain bus service ctx := context.Background() - bs := NewBusService(ctx, addr, CheckInterval) + bs := NewBusService(ctx, addr, conf.GConf.ChainBusPeriod) dbms.busService = bs // private key cache @@ -185,51 +181,11 @@ func (dbms *DBMS) Init() (err error) { err = errors.Wrap(err, "init chain bus failed") return } - if err = dbms.busService.Subscribe("/UpdatePermission/", dbms.updatePermission); err != nil { - err = errors.Wrap(err, "init chain bus failed") - return - } - if err = dbms.busService.Subscribe("/UpdateBilling/", dbms.updateBilling); err != nil { - err = errors.Wrap(err, "init chain bus failed") - return - } dbms.busService.Start() return } -func (dbms *DBMS) updateBilling(tx interfaces.Transaction, count uint32) { - ub, ok := tx.(*types.UpdateBilling) - if !ok { - log.WithError(ErrInvalidTransactionType).Warningf("invalid tx type in updateBilling: %s", - tx.GetTransactionType().String()) - return - } - - var ( - dbID = ub.Receiver.DatabaseID() - newState = types.UserState{ - State: make(map[proto.AccountAddress]*types.PermStat), - } - ) - - p, ok := dbms.busService.RequestSQLProfile(dbID) - if !ok { - log.WithFields(log.Fields{ - "databaseid": dbID, - }).Warning("database profile not found") - return - } - - for _, user := range p.Users { - newState.State[user.Address] = &types.PermStat{ - Permission: user.Permission, - Status: user.Status, - } - } - dbms.chainMap.Store(ub.Receiver.DatabaseID(), newState) -} - func (dbms *DBMS) createDatabase(tx interfaces.Transaction, count uint32) { cd, ok := tx.(*types.CreateDatabase) if !ok { @@ -267,16 +223,6 @@ func (dbms *DBMS) createDatabase(tx interfaces.Transaction, count uint32) { return } - state := types.NewUserState() - for _, user := range p.Users { - log.Debugf("user address: %s, permission: %d, status: %d", - user.Address.String(), user.Permission, user.Status) - state.State[user.Address] = &types.PermStat{ - Permission: user.Permission, - Status: user.Status, - } - } - var si, err = dbms.buildSQLChainServiceInstance(p) if err != nil { log.WithError(err).Warn("failed to build sqlchain service instance from profile") @@ -285,7 +231,6 @@ func (dbms *DBMS) createDatabase(tx interfaces.Transaction, count uint32) { if err != nil { log.WithError(err).Error("create database error") } - dbms.chainMap.Store(dbID, *state) } func (dbms *DBMS) buildSQLChainServiceInstance( @@ -326,32 +271,46 @@ func (dbms *DBMS) buildSQLChainServiceInstance( return } -func (dbms *DBMS) updatePermission(tx interfaces.Transaction, count uint32) { - up, ok := tx.(*types.UpdatePermission) +// UpdatePermission exports the update permission interface for test. +func (dbms *DBMS) UpdatePermission(dbID proto.DatabaseID, user proto.AccountAddress, permStat *types.PermStat) (err error) { + dbms.busService.lock.Lock() + defer dbms.busService.lock.Unlock() + profile, ok := dbms.busService.sqlChainProfiles[dbID] if !ok { - log.WithError(ErrInvalidTransactionType).Warning("unexpected error in updatePermission") - return + dbms.busService.sqlChainProfiles[dbID] = &types.SQLChainProfile{ + ID: dbID, + Users: []*types.SQLChainUser{ + &types.SQLChainUser{ + Address: user, + Permission: permStat.Permission, + Status: permStat.Status, + }, + }, + } + } else { + exist := false + for _, u := range profile.Users { + u.Address = user + u.Permission = permStat.Permission + u.Status = permStat.Status + exist = true + } + if !exist { + profile.Users = append(profile.Users, &types.SQLChainUser{ + Address: user, + Permission: permStat.Permission, + Status: permStat.Status, + }) + dbms.busService.sqlChainProfiles[dbID] = profile + } } - state, loaded := dbms.chainMap.Load(up.TargetSQLChain.DatabaseID()) - if !loaded { - return + _, ok = dbms.busService.sqlChainState[dbID] + if !ok { + dbms.busService.sqlChainState[dbID] = make(map[proto.AccountAddress]*types.PermStat) } + dbms.busService.sqlChainState[dbID][user] = permStat - newState := state.(types.UserState) - newState.AddPermission(up.TargetUser, up.Permission) - dbms.chainMap.Store(up.TargetSQLChain.DatabaseID(), newState) -} - -// UpdatePermission exports the update permission interface for test. -func (dbms *DBMS) UpdatePermission(dbID proto.DatabaseID, user proto.AccountAddress, permStat *types.PermStat) (err error) { - s, loaded := dbms.chainMap.Load(dbID) - if !loaded { - err = errors.Wrap(ErrNotExists, "update permission failed") - return - } - state := s.(types.UserState) - state.State[user] = permStat return } @@ -421,15 +380,14 @@ func (dbms *DBMS) Create(instance *types.ServiceInstance, cleanup bool) (err err // new db dbCfg := &DBConfig{ - DatabaseID: instance.DatabaseID, - DataDir: rootDir, - KayakMux: dbms.kayakMux, - ChainMux: dbms.chainMux, - MaxWriteTimeGap: dbms.cfg.MaxReqTimeGap, - EncryptionKey: instance.ResourceMeta.EncryptionKey, - SpaceLimit: instance.ResourceMeta.Space, - // TODO(lambda): make BillingPeriod Configurable - UpdatePeriod: uint64(conf.GConf.BillingPeriod), + DatabaseID: instance.DatabaseID, + DataDir: rootDir, + KayakMux: dbms.kayakMux, + ChainMux: dbms.chainMux, + MaxWriteTimeGap: dbms.cfg.MaxReqTimeGap, + EncryptionKey: instance.ResourceMeta.EncryptionKey, + SpaceLimit: instance.ResourceMeta.Space, + UpdateBlockCount: conf.GConf.BillingBlockCount, UseEventualConsistency: instance.ResourceMeta.UseEventualConsistency, ConsistencyLevel: instance.ResourceMeta.ConsistencyLevel, SlowQueryTime: DefaultSlowQueryTime, @@ -442,11 +400,6 @@ func (dbms *DBMS) Create(instance *types.ServiceInstance, cleanup bool) (err err // add to meta err = dbms.addMeta(instance.DatabaseID, db) - // init chainMap - dbms.chainMap.Store(instance.DatabaseID, types.UserState{ - State: make(map[proto.AccountAddress]*types.PermStat), - }) - return } @@ -548,43 +501,30 @@ func (dbms *DBMS) removeMeta(dbID proto.DatabaseID) (err error) { func (dbms *DBMS) checkPermission(addr proto.AccountAddress, dbID proto.DatabaseID, queryType types.QueryType) (err error) { log.Debugf("in checkPermission, database id: %s, user addr: %s", dbID, addr.String()) - state, loaded := dbms.chainMap.Load(dbID) - if !loaded { - err = errors.Wrap(ErrNotExists, "check permission failed") - return - } - - var ( - s = state.(types.UserState) - ) - if permStat, ok := s.State[addr]; ok { + if permStat, ok := dbms.busService.RequestPermStat(dbID, addr); ok { if !permStat.Status.EnableQuery() { - err = ErrPermissionDeny - log.WithError(err).Debugf("cannot query, status: %d", permStat.Status) + err = errors.Wrapf(ErrPermissionDeny, "cannot query, status: %d", permStat.Status) return } if queryType == types.ReadQuery { if !permStat.Permission.CheckRead() { - err = ErrPermissionDeny - log.WithError(err).Debugf("cannot read, permission: %d", permStat.Permission) + err = errors.Wrapf(ErrPermissionDeny, "cannot read, permission: %d", permStat.Permission) return } } else if queryType == types.WriteQuery { if !permStat.Permission.CheckWrite() { - err = ErrPermissionDeny - log.WithError(err).Debugf("cannot write, permission: %d", permStat.Permission) + err = errors.Wrapf(ErrPermissionDeny, "cannot write, permission: %d", permStat.Permission) return } } else { - err = ErrInvalidPermission - log.WithError(err).Debugf("invalid permission, permission: %d", permStat.Permission) + err = errors.Wrapf(ErrInvalidPermission, + "invalid permission, permission: %d", permStat.Permission) return } } else { - err = ErrPermissionDeny - log.WithError(err).Debug("cannot find permission") + err = errors.Wrap(ErrPermissionDeny, "database not exists") return } @@ -609,6 +549,14 @@ func (dbms *DBMS) addTxSubscription(dbID proto.DatabaseID, nodeID proto.NodeID, }).WithError(err).Warning("generate addr failed in addTxSubscription") return } + + log.WithFields(log.Fields{ + "dbID": dbID, + "nodeID": nodeID, + "addr": addr.String(), + "startHeight": startHeight, + }).Debugf("addTxSubscription") + err = dbms.checkPermission(addr, dbID, types.ReadQuery) if err != nil { log.WithFields(log.Fields{"databaseID": dbID, "addr": addr}).WithError(err).Warning("permission deny") diff --git a/worker/dbms_rpc.go b/worker/dbms_rpc.go index 86c5f26c1..1fd40fd2a 100644 --- a/worker/dbms_rpc.go +++ b/worker/dbms_rpc.go @@ -34,23 +34,26 @@ var ( // SubscribeTransactionsReq defines a request of SubscribeTransaction RPC method. type SubscribeTransactionsReq struct { - DatabaseID proto.DatabaseID - SubscriberID proto.NodeID - Height int32 + proto.Envelope + DatabaseID proto.DatabaseID + Height int32 } // SubscribeTransactionsResp defines a response of SubscribeTransaction RPC method. type SubscribeTransactionsResp struct { + proto.Envelope } // CancelSubscriptionReq defines a request of CancelSubscription RPC method. type CancelSubscriptionReq struct { - DatabaseID proto.DatabaseID - SubscriberID proto.NodeID + proto.Envelope + DatabaseID proto.DatabaseID } // CancelSubscriptionResp defines a response of CancelSubscription RPC method. -type CancelSubscriptionResp struct{} +type CancelSubscriptionResp struct { + proto.Envelope +} // DBMSRPCService is the rpc endpoint of database management. type DBMSRPCService struct { @@ -154,12 +157,14 @@ func (rpc *DBMSRPCService) Deploy(req *types.UpdateService, _ *types.UpdateServi // SubscribeTransactions is the RPC method to fetch subscribe new packed and confirmed transactions from the target server. func (rpc *DBMSRPCService) SubscribeTransactions(req *SubscribeTransactionsReq, resp *SubscribeTransactionsResp) (err error) { - err = rpc.dbms.addTxSubscription(req.DatabaseID, req.SubscriberID, req.Height) + subscribeID := req.GetNodeID().ToNodeID() + err = rpc.dbms.addTxSubscription(req.DatabaseID, subscribeID, req.Height) return } // CancelSubscription is the RPC method to cancel subscription in the target server. func (rpc *DBMSRPCService) CancelSubscription(req *CancelSubscriptionReq, _ *CancelSubscriptionResp) (err error) { - err = rpc.dbms.cancelTxSubscription(req.DatabaseID, req.SubscriberID) + nodeID := req.GetNodeID().ToNodeID() + err = rpc.dbms.cancelTxSubscription(req.DatabaseID, nodeID) return } diff --git a/worker/dbms_test.go b/worker/dbms_test.go index 65a1efbc7..4895b024f 100644 --- a/worker/dbms_test.go +++ b/worker/dbms_test.go @@ -30,7 +30,6 @@ import ( "github.com/CovenantSQL/CovenantSQL/route" "github.com/CovenantSQL/CovenantSQL/rpc" "github.com/CovenantSQL/CovenantSQL/types" - "github.com/pkg/errors" . "github.com/smartystreets/goconvey/convey" ) @@ -67,6 +66,7 @@ func TestDBMS(t *testing.T) { // init err = dbms.Init() So(err, ShouldBeNil) + dbms.busService.Stop() // add database var req *types.UpdateService @@ -119,7 +119,7 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, writeQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) // sending read query var readQuery *types.Request @@ -129,31 +129,17 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, readQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) }) - // grant read permission - up := &types.UpdatePermission{ - UpdatePermissionHeader: types.UpdatePermissionHeader{ - TargetSQLChain: dbAddr, - TargetUser: userAddr, - Permission: types.Write, - }, - } - err = up.Sign(privateKey) + // grant write and read permission + err = dbms.UpdatePermission(dbAddr.DatabaseID(), userAddr, + &types.PermStat{Permission: types.Write, Status: types.Normal}) So(err, ShouldBeNil) - dbms.updatePermission(up, 0) - us, ok := dbms.chainMap.Load(dbID) + userState, ok := dbms.busService.RequestPermStat(dbAddr.DatabaseID(), userAddr) So(ok, ShouldBeTrue) - userState := us.(types.UserState) - perm, ok := userState.GetPermission(userAddr) - So(ok, ShouldBeTrue) - So(perm, ShouldEqual, types.Write) - stat, ok := userState.GetStatus(userAddr) - So(ok, ShouldBeTrue) - So(stat, ShouldEqual, types.UnknownStatus) - userState.UpdateStatus(userAddr, types.Normal) - dbms.chainMap.Store(dbID, userState) + So(userState.Permission, ShouldEqual, types.Write) + So(userState.Status, ShouldEqual, types.Normal) Convey("success write and read", func() { // sending write query @@ -199,23 +185,19 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = dbms.addTxSubscription(dbID2, nodeID, 1) - So(errors.Cause(err), ShouldEqual, ErrNotExists) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) err = dbms.addTxSubscription(dbID, nodeID, 1) So(err, ShouldBeNil) err = dbms.cancelTxSubscription(dbID, nodeID) So(err, ShouldBeNil) - // grant read permission - up = &types.UpdatePermission{ - UpdatePermissionHeader: types.UpdatePermissionHeader{ - TargetSQLChain: dbAddr, - TargetUser: userAddr, - Permission: types.Read, - }, - } - err = up.Sign(privateKey) - So(err, ShouldBeNil) - dbms.updatePermission(up, 0) + // revoke write permission + err = dbms.UpdatePermission(dbAddr.DatabaseID(), userAddr, + &types.PermStat{Permission: types.Read, Status: types.Normal}) + userState, ok := dbms.busService.RequestPermStat(dbAddr.DatabaseID(), userAddr) + So(ok, ShouldBeTrue) + So(userState.Permission, ShouldEqual, types.Read) + So(userState.Status, ShouldEqual, types.Normal) Convey("success reading and fail to write", func() { // sending write query @@ -228,7 +210,7 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, writeQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) // sending read query var readQuery *types.Request @@ -246,16 +228,12 @@ func TestDBMS(t *testing.T) { }) // grant invalid permission - up = &types.UpdatePermission{ - UpdatePermissionHeader: types.UpdatePermissionHeader{ - TargetSQLChain: dbAddr, - TargetUser: userAddr, - Permission: types.NumberOfUserPermission, - }, - } - err = up.Sign(privateKey) - So(err, ShouldBeNil) - dbms.updatePermission(up, 0) + err = dbms.UpdatePermission(dbAddr.DatabaseID(), userAddr, + &types.PermStat{Permission: types.Void, Status: types.Normal}) + userState, ok = dbms.busService.RequestPermStat(dbAddr.DatabaseID(), userAddr) + So(ok, ShouldBeTrue) + So(userState.Permission, ShouldEqual, types.Void) + So(userState.Status, ShouldEqual, types.Normal) Convey("invalid permission query should fail", func() { // sending write query @@ -268,7 +246,7 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, writeQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) // sending read query var readQuery *types.Request @@ -278,19 +256,19 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, readQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) err = dbms.addTxSubscription(dbID, nodeID, 1) - So(err, ShouldEqual, ErrPermissionDeny) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) }) - // switch user to arrears - us, ok = dbms.chainMap.Load(dbID) + // grant admin permission but in arrears + err = dbms.UpdatePermission(dbAddr.DatabaseID(), userAddr, + &types.PermStat{Permission: types.Admin, Status: types.Arrears}) + userState, ok = dbms.busService.RequestPermStat(dbAddr.DatabaseID(), userAddr) So(ok, ShouldBeTrue) - userState = us.(types.UserState) - userState.UpdatePermission(userAddr, types.Admin) - userState.UpdateStatus(userAddr, types.Arrears) - dbms.chainMap.Store(dbID, userState) + So(userState.Permission, ShouldEqual, types.Admin) + So(userState.Status, ShouldEqual, types.Arrears) Convey("arrears query should fail", func() { // sending write query @@ -303,7 +281,7 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, writeQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) // sending read query var readQuery *types.Request @@ -313,17 +291,18 @@ func TestDBMS(t *testing.T) { So(err, ShouldBeNil) err = testRequest(route.DBSQuery, readQuery, &queryRes) - So(err.Error(), ShouldEqual, ErrPermissionDeny.Error()) + So(err.Error(), ShouldContainSubstring, ErrPermissionDeny.Error()) }) // switch user to normal - us, ok = dbms.chainMap.Load(dbID) + err = dbms.UpdatePermission(dbAddr.DatabaseID(), userAddr, + &types.PermStat{Permission: types.Admin, Status: types.Normal}) + userState, ok = dbms.busService.RequestPermStat(dbAddr.DatabaseID(), userAddr) So(ok, ShouldBeTrue) - userState = us.(types.UserState) - userState.UpdateStatus(userAddr, types.Normal) - dbms.chainMap.Store(dbID, userState) + So(userState.Permission, ShouldEqual, types.Admin) + So(userState.Status, ShouldEqual, types.Normal) - Convey("queries", func() { + Convey("can send read and write queries", func() { // sending write query var writeQuery *types.Request var queryRes *types.Response diff --git a/worker/errors.go b/worker/errors.go index 56d6b7473..00677621d 100644 --- a/worker/errors.go +++ b/worker/errors.go @@ -21,34 +21,22 @@ import "errors" var ( // ErrInvalidRequest defines invalid request structure during request. ErrInvalidRequest = errors.New("invalid request supplied") - // ErrInvalidRequestSeq defines invalid sequence no of request. ErrInvalidRequestSeq = errors.New("invalid request sequence applied") - - // ErrMultipleQuery defines error on executing multiple select query in single request. - ErrMultipleQuery = errors.New("multiple query in single request") - // ErrAlreadyExists defines error on re-creating existing database instance. ErrAlreadyExists = errors.New("database instance already exists") - // ErrNotExists defines errors on manipulating a non-exists database instance. ErrNotExists = errors.New("database instance not exists") - // ErrInvalidDBConfig defines errors on received invalid db config from block producer. ErrInvalidDBConfig = errors.New("invalid database configuration") - // ErrSpaceLimitExceeded defines errors on disk space exceeding limit. ErrSpaceLimitExceeded = errors.New("space limit exceeded") - // ErrUnknownMuxRequest indicates that the a multiplexing request endpoint is not found. ErrUnknownMuxRequest = errors.New("unknown multiplexing request") - // ErrPermissionDeny indicates that the requester has no permission to send read or write query. ErrPermissionDeny = errors.New("permission deny") - // ErrInvalidPermission indicates that the requester sends a unrecognized permission. ErrInvalidPermission = errors.New("invalid permission") - // ErrInvalidTransactionType indicates that the transaction type is invalid. ErrInvalidTransactionType = errors.New("invalid transaction type") ) diff --git a/worker/helper_test.go b/worker/helper_test.go index 680760b28..e7b48b14f 100644 --- a/worker/helper_test.go +++ b/worker/helper_test.go @@ -20,6 +20,7 @@ import ( "sync/atomic" "github.com/CovenantSQL/CovenantSQL/blockproducer/interfaces" + "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/types" ) @@ -28,29 +29,47 @@ var ( testEventProfiles = []*types.SQLChainProfile{ &types.SQLChainProfile{ ID: proto.DatabaseID("111"), + Users: []*types.SQLChainUser{ + testUser1, + }, }, &types.SQLChainProfile{ ID: proto.DatabaseID("222"), + Users: []*types.SQLChainUser{ + testUser2, + }, }, &types.SQLChainProfile{ ID: proto.DatabaseID("333"), + Users: []*types.SQLChainUser{ + testUser3, + }, }, &types.SQLChainProfile{ ID: proto.DatabaseID("444"), - }, - &types.SQLChainProfile{ - ID: proto.DatabaseID("555"), + Users: []*types.SQLChainUser{ + testUser4, + }, }, } testOddProfiles = []*types.SQLChainProfile{ &types.SQLChainProfile{ - ID: proto.DatabaseID("777"), + ID: proto.DatabaseID("111"), + Users: []*types.SQLChainUser{ + testUser4, + }, }, &types.SQLChainProfile{ - ID: proto.DatabaseID("888"), + ID: proto.DatabaseID("222"), + Users: []*types.SQLChainUser{ + testUser3, + }, }, &types.SQLChainProfile{ - ID: proto.DatabaseID("999"), + ID: proto.DatabaseID("333"), + Users: []*types.SQLChainUser{ + testUser2, + }, }, } testEventBlocks = types.BPBlock{ @@ -75,8 +94,30 @@ var ( &types.Transfer{}, }, } - testEventID = proto.DatabaseID("111") - testOddID = proto.DatabaseID("777") + testID = proto.DatabaseID("111") + testNotExistID = proto.DatabaseID("not exist") + testAddr = proto.AccountAddress(hash.THashH([]byte{'a', 'd', 'd', 'r', '1'})) + testNotExistAddr = proto.AccountAddress(hash.THashH([]byte{'a', 'a'})) + testUser1 = &types.SQLChainUser{ + Address: testAddr, + Permission: types.Write, + Status: types.Normal, + } + testUser2 = &types.SQLChainUser{ + Address: testAddr, + Permission: types.Read, + Status: types.Arrears, + } + testUser3 = &types.SQLChainUser{ + Address: testAddr, + Permission: types.Write, + Status: types.Reminder, + } + testUser4 = &types.SQLChainUser{ + Address: testAddr, + Permission: types.Read, + Status: types.Arbitration, + } ) type blockInfo struct { diff --git a/xenomint/chain.go b/xenomint/chain.go index 830ab2a0c..85193ce96 100644 --- a/xenomint/chain.go +++ b/xenomint/chain.go @@ -20,36 +20,14 @@ import ( "time" ca "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" - "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/crypto/kms" "github.com/CovenantSQL/CovenantSQL/proto" "github.com/CovenantSQL/CovenantSQL/types" "github.com/CovenantSQL/CovenantSQL/utils/log" xi "github.com/CovenantSQL/CovenantSQL/xenomint/interfaces" xs "github.com/CovenantSQL/CovenantSQL/xenomint/sqlite" - xt "github.com/CovenantSQL/CovenantSQL/xenomint/types" ) -const ( - inCommandBufferLength = 100000 - outCommandBufferLength = 100000 -) - -type applyRequest struct { - request *types.Request - response *types.Response -} - -type blockNode struct { - parent *blockNode - // Cached block fields - hash hash.Hash - count int32 - height int32 - // Cached block object, may be nil - block *xt.Block -} - // Chain defines the xenomint chain structure. type Chain struct { state *State diff --git a/xenomint/errors.go b/xenomint/errors.go index 9a8ec2dea..6d0ce64f9 100644 --- a/xenomint/errors.go +++ b/xenomint/errors.go @@ -25,14 +25,8 @@ var ( ErrMissingParent = errors.New("query missing parent") // ErrInvalidRequest indicates the query is invalid. ErrInvalidRequest = errors.New("invalid request") - // ErrQueryExists indicates the query already exists in pool. - ErrQueryExists = errors.New("query already exists") - // ErrStateClosed indicates the state is closed. - ErrStateClosed = errors.New("state is closed") // ErrQueryConflict indicates the there is a conflict on query replay. ErrQueryConflict = errors.New("query conflict") - // ErrLocalBehindRemote indicates the local state is behind the remote. - ErrLocalBehindRemote = errors.New("local state is behind the remote") // ErrMuxServiceNotFound indicates that the multiplexing service endpoint is not found. ErrMuxServiceNotFound = errors.New("mux service not found") // ErrStatefulQueryParts indicates query contains stateful query parts. diff --git a/xenomint/xxx_test.go b/xenomint/xxx_test.go index 13a973878..eb2eaf603 100644 --- a/xenomint/xxx_test.go +++ b/xenomint/xxx_test.go @@ -22,6 +22,7 @@ import ( "os" "path" "sync/atomic" + //"runtime/trace" "sync" "syscall" @@ -156,21 +157,6 @@ type keygen interface { reset() } -type randKeygen struct { - offset int - length int -} - -func newRandKeygen(offset, length int) *randKeygen { - return &randKeygen{ - offset: offset, - length: length, - } -} - -func (k *randKeygen) next() int { return rand.Intn(k.length) + k.offset } -func (k *randKeygen) reset() {} - type permKeygen struct { offset int length int