merge from dev-upgrade

This commit is contained in:
liam.lai 2024-12-27 10:03:54 -08:00
commit 77f9cc59ec
612 changed files with 26661 additions and 33612 deletions

2
.github/CODEOWNERS vendored
View file

@ -7,6 +7,4 @@ core/ @karalabe @holiman
eth/ @karalabe eth/ @karalabe
les/ @zsfelfoldi les/ @zsfelfoldi
light/ @zsfelfoldi light/ @zsfelfoldi
mobile/ @karalabe
p2p/ @fjl @zsfelfoldi p2p/ @fjl @zsfelfoldi
whisper/ @gballet @gluk256

View file

@ -55,7 +55,7 @@ jobs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
cache: false cache: false
go-version: '1.21.x' go-version: '1.22.x'
- name: Run tests - name: Run tests
run: ${{ matrix.script }} run: ${{ matrix.script }}
env: env:

View file

@ -1,180 +0,0 @@
sudo: required
language: go
go_import_path: github.com/XinFinOrg/XDPoSChain
on:
branches:
- master
- dev-upgrade
tags: true
env:
global:
- GOPROXY=https://proxy.golang.org
- GO111MODULE=on
# Terraform env
- tf_version=1.3.0
# Setting terraform init CLI options - https://www.terraform.io/docs/commands/init.html
- tf_init_cli_options=" -input=false"
# Set terraform validation CLI options - https://www.terraform.io/docs/commands/validate.html
- tf_validation_cli_options=""
# Set terraform plan CLI options - https://www.terraform.io/docs/commands/plan.html
- tf_plan_cli_options=" -lock=false -input=false"
# Set terraform apply CLI options - https://www.terraform.io/docs/commands/apply.html
- tf_apply_cli_options=" -auto-approve -input=false"
jobs:
include:
- stage: Tests
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: A-B tests
script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[a-b].*")
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[a-m].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: C-[a-m] tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[n-o].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: C-[n-o] tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[p-z].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: C-[p-z] tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[d-i].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: D-I tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[j-n].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: J-N tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[o-r].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: O-R tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/s.*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: S tests
- script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[t-z].*")
os: linux
dist: bionic
go: 1.21.x
env:
- GO111MODULE=auto
name: T-Z tests
- stage: TAG Build
if: tag IS present
services:
- docker
install: skip
before_script:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker --version # document the version travis is using
- docker build -t xinfinorg/xdposchain:$TRAVIS_TAG -f cicd/Dockerfile .
script:
- docker push xinfinorg/xdposchain:$TRAVIS_TAG
- stage: (Devnet) Build, and push images
if: branch = dev-upgrade AND type = push AND tag IS blank
services:
- docker
install: skip
before_script:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker --version # document the version travis is using
- docker pull xinfinorg/devnet:latest # build the "previous" tag so that our devnet environment can run with both old and new code at the same time.
- docker tag xinfinorg/devnet:latest xinfinorg/devnet:previous
- docker rmi xinfinorg/devnet:latest
- docker build -t xinfinorg/devnet:latest -f cicd/Dockerfile .
script:
- docker push xinfinorg/devnet:latest
- docker push xinfinorg/devnet:previous
- stage: (Devnet)Terraform plan
if: branch = dev-upgrade AND type = push AND tag IS blank
dist: xenial
language: bash
install:
- wget https://releases.hashicorp.com/terraform/"$tf_version"/terraform_"$tf_version"_linux_amd64.zip
- unzip terraform_"$tf_version"_linux_amd64.zip
- sudo mv terraform /usr/local/bin/
- rm terraform_"$tf_version"_linux_amd64.zip
script:
- echo "Pull request detected, creating change plan(Devnet)"
- cd cicd/devnet/terraform
# Terraform init, validate, then create change plan. If any fail, fail validation
- terraform init $tf_init_cli_options
- terraform validate $tf_validation_cli_options
- terraform plan $tf_plan_cli_options
- stage: (Devnet) Terraform apply
if: branch = dev-upgrade AND type = push AND tag IS blank
dist: xenial
language: bash
install:
# Download and install terraform before each run
- wget https://releases.hashicorp.com/terraform/"$tf_version"/terraform_"$tf_version"_linux_amd64.zip
- unzip terraform_"$tf_version"_linux_amd64.zip
- sudo mv terraform /usr/local/bin/
- rm terraform_"$tf_version"_linux_amd64.zip
- curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
- unzip awscliv2.zip
- sudo ./aws/install
- export PATH=$PATH:$HOME/.local/bin # put aws in the path
script:
- echo "Merge detected, executing changes(Devnet)"
- cd cicd/devnet/terraform
# Terraform init and then apply changes to environment
- terraform init $tf_init_cli_options
- terraform apply $tf_apply_cli_options
- sleep 5
- |
source .env
for ((i=$us_east_2_start;i<$us_east_2_end;i++)); do
echo "Force deploy xdc-$i"
aws ecs update-service --region us-east-2 --cluster devnet-xdcnode-cluster --service ecs-service-xdc$i --force-new-deployment --no-cli-pager;
done
for ((i=$eu_west_1_start;i<$eu_west_1_end;i++)); do
echo "Force deploy xdc-$i"
aws ecs update-service --region eu-west-1 --cluster devnet-xdcnode-cluster --service ecs-service-xdc$i --force-new-deployment --no-cli-pager;
done
for ((i=$ap_southeast_2_start;i<$ap_southeast_2_end;i++)); do
echo "Force deploy xdc-$i"
aws ecs update-service --region ap-southeast-2 --cluster devnet-xdcnode-cluster --service ecs-service-xdc$i --force-new-deployment --no-cli-pager;
done
aws ecs update-service --region ap-southeast-1 --cluster devnet-xdcnode-cluster --service ecs-service-rpc1 --force-new-deployment --no-cli-pager;
- stage: (Devnet) Send Deployment Notification
if: branch = dev-upgrade AND type = push AND tag IS blank
language: bash
script:
- curl --location --request POST "66.94.98.186:8080/deploy?environment=devnet&service=xdc&version=$TRAVIS_COMMIT"

View file

@ -1,4 +1,4 @@
FROM golang:1.21-alpine as builder FROM golang:1.22-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git RUN apk add --no-cache make gcc musl-dev linux-headers git

View file

@ -1,4 +1,4 @@
FROM golang:1.21-alpine as builder FROM golang:1.22-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers RUN apk add --no-cache make gcc musl-dev linux-headers

View file

@ -1,4 +1,4 @@
FROM golang:1.21-alpine as builder FROM golang:1.22-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git RUN apk add --no-cache make gcc musl-dev linux-headers git

View file

@ -4,7 +4,7 @@
GOBIN = $(shell pwd)/build/bin GOBIN = $(shell pwd)/build/bin
GOFMT = gofmt GOFMT = gofmt
GO ?= 1.21.3 GO ?= 1.22.10
GO_PACKAGES = . GO_PACKAGES = .
GO_FILES := $(shell find $(shell go list -f '{{.Dir}}' $(GO_PACKAGES)) -name \*.go) GO_FILES := $(shell find $(shell go list -f '{{.Dir}}' $(GO_PACKAGES)) -name \*.go)

View file

@ -10,6 +10,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxDAO" "github.com/XinFinOrg/XDPoSChain/XDCxDAO"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
@ -17,7 +18,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/p2p" "github.com/XinFinOrg/XDPoSChain/p2p"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/sync/syncmap" "golang.org/x/sync/syncmap"
) )
@ -59,8 +59,8 @@ type XDCX struct {
sdkNode bool sdkNode bool
settings syncmap.Map // holds configuration settings that can be dynamically changed settings syncmap.Map // holds configuration settings that can be dynamically changed
tokenDecimalCache *lru.Cache tokenDecimalCache *lru.Cache[common.Address, *big.Int]
orderCache *lru.Cache orderCache *lru.Cache[common.Hash, map[common.Hash]tradingstate.OrderHistoryItem]
} }
func (XDCx *XDCX) Protocols() []p2p.Protocol { func (XDCx *XDCX) Protocols() []p2p.Protocol {
@ -94,19 +94,11 @@ func NewMongoDBEngine(cfg *Config) *XDCxDAO.MongoDatabase {
} }
func New(cfg *Config) *XDCX { func New(cfg *Config) *XDCX {
tokenDecimalCache, err := lru.New(defaultCacheLimit)
if err != nil {
log.Warn("[XDCx-New] fail to create new lru for token decimal", "error", err)
}
orderCache, err := lru.New(tradingstate.OrderCacheLimit)
if err != nil {
log.Warn("[XDCx-New] fail to create new lru for order", "error", err)
}
XDCX := &XDCX{ XDCX := &XDCX{
orderNonce: make(map[common.Address]*big.Int), orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil), Triegc: prque.New(nil),
tokenDecimalCache: tokenDecimalCache, tokenDecimalCache: lru.NewCache[common.Address, *big.Int](defaultCacheLimit),
orderCache: orderCache, orderCache: lru.NewCache[common.Hash, map[common.Hash]tradingstate.OrderHistoryItem](tradingstate.OrderCacheLimit),
} }
// default DBEngine: levelDB // default DBEngine: levelDB
@ -275,11 +267,11 @@ func (XDCx *XDCX) GetAveragePriceLastEpoch(chain consensus.ChainContext, statedb
if inversePrice != nil && inversePrice.Sign() > 0 { if inversePrice != nil && inversePrice.Sign() > 0 {
quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, quoteToken) quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, quoteToken)
if err != nil || quoteTokenDecimal.Sign() == 0 { if err != nil || quoteTokenDecimal.Sign() == 0 {
return nil, fmt.Errorf("fail to get tokenDecimal. Token: %v . Err: %v", quoteToken.String(), err) return nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", quoteToken.String(), err)
} }
baseTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, baseToken) baseTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, baseToken)
if err != nil || baseTokenDecimal.Sign() == 0 { if err != nil || baseTokenDecimal.Sign() == 0 {
return nil, fmt.Errorf("fail to get tokenDecimal. Token: %v . Err: %v", baseToken.String(), err) return nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", baseToken.String(), err)
} }
price = new(big.Int).Mul(baseTokenDecimal, quoteTokenDecimal) price = new(big.Int).Mul(baseTokenDecimal, quoteTokenDecimal)
price = new(big.Int).Div(price, inversePrice) price = new(big.Int).Div(price, inversePrice)
@ -302,7 +294,7 @@ func (XDCx *XDCX) ConvertXDCToToken(chain consensus.ChainContext, statedb *state
tokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, token) tokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, token)
if err != nil || tokenDecimal.Sign() == 0 { if err != nil || tokenDecimal.Sign() == 0 {
return common.Big0, common.Big0, fmt.Errorf("fail to get tokenDecimal. Token: %v . Err: %v", token.String(), err) return common.Big0, common.Big0, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", token.String(), err)
} }
tokenQuantity := new(big.Int).Mul(quantity, tokenDecimal) tokenQuantity := new(big.Int).Mul(quantity, tokenDecimal)
tokenQuantity = new(big.Int).Div(tokenQuantity, tokenPriceInXDC) tokenQuantity = new(big.Int).Div(tokenQuantity, tokenPriceInXDC)
@ -568,7 +560,7 @@ func (XDCx *XDCX) GetTradingState(block *types.Block, author common.Address) (*t
return nil, err return nil, err
} }
if XDCx.StateCache == nil { if XDCx.StateCache == nil {
return nil, errors.New("Not initialized XDCx") return nil, errors.New("not initialized XDCx")
} }
return tradingstate.New(root, XDCx.StateCache) return tradingstate.New(root, XDCx.StateCache)
} }
@ -607,12 +599,9 @@ func (XDCx *XDCX) GetTradingStateRoot(block *types.Block, author common.Address)
} }
func (XDCx *XDCX) UpdateOrderCache(baseToken, quoteToken common.Address, orderHash common.Hash, txhash common.Hash, lastState tradingstate.OrderHistoryItem) { func (XDCx *XDCX) UpdateOrderCache(baseToken, quoteToken common.Address, orderHash common.Hash, txhash common.Hash, lastState tradingstate.OrderHistoryItem) {
var orderCacheAtTxHash map[common.Hash]tradingstate.OrderHistoryItem orderCacheAtTxHash, ok := XDCx.orderCache.Get(txhash)
c, ok := XDCx.orderCache.Get(txhash) if !ok || orderCacheAtTxHash == nil {
if !ok || c == nil {
orderCacheAtTxHash = make(map[common.Hash]tradingstate.OrderHistoryItem) orderCacheAtTxHash = make(map[common.Hash]tradingstate.OrderHistoryItem)
} else {
orderCacheAtTxHash = c.(map[common.Hash]tradingstate.OrderHistoryItem)
} }
orderKey := tradingstate.GetOrderHistoryKey(baseToken, quoteToken, orderHash) orderKey := tradingstate.GetOrderHistoryKey(baseToken, quoteToken, orderHash)
_, ok = orderCacheAtTxHash[orderKey] _, ok = orderCacheAtTxHash[orderKey]
@ -629,16 +618,15 @@ func (XDCx *XDCX) RollbackReorgTxMatch(txhash common.Hash) error {
items := db.GetListItemByTxHash(txhash, &tradingstate.OrderItem{}) items := db.GetListItemByTxHash(txhash, &tradingstate.OrderItem{})
if items != nil { if items != nil {
for _, order := range items.([]*tradingstate.OrderItem) { for _, order := range items.([]*tradingstate.OrderItem) {
c, ok := XDCx.orderCache.Get(txhash) orderCacheAtTxHash, ok := XDCx.orderCache.Get(txhash)
log.Debug("XDCx reorg: rollback order", "txhash", txhash.Hex(), "order", tradingstate.ToJSON(order), "orderHistoryItem", c) log.Debug("XDCx reorg: rollback order", "txhash", txhash.Hex(), "order", tradingstate.ToJSON(order), "orderHistoryItem", orderCacheAtTxHash)
if !ok { if !ok || orderCacheAtTxHash == nil {
log.Debug("XDCx reorg: remove order due to no orderCache", "order", tradingstate.ToJSON(order)) log.Debug("XDCx reorg: remove order due to no orderCache", "order", tradingstate.ToJSON(order))
if err := db.DeleteObject(order.Hash, &tradingstate.OrderItem{}); err != nil { if err := db.DeleteObject(order.Hash, &tradingstate.OrderItem{}); err != nil {
log.Crit("SDKNode: failed to remove reorg order", "err", err.Error(), "order", tradingstate.ToJSON(order)) log.Crit("SDKNode: failed to remove reorg order", "err", err.Error(), "order", tradingstate.ToJSON(order))
} }
continue continue
} }
orderCacheAtTxHash := c.(map[common.Hash]tradingstate.OrderHistoryItem)
orderHistoryItem := orderCacheAtTxHash[tradingstate.GetOrderHistoryKey(order.BaseToken, order.QuoteToken, order.Hash)] orderHistoryItem := orderCacheAtTxHash[tradingstate.GetOrderHistoryKey(order.BaseToken, order.QuoteToken, order.Hash)]
if (orderHistoryItem == tradingstate.OrderHistoryItem{}) { if (orderHistoryItem == tradingstate.OrderHistoryItem{}) {
log.Debug("XDCx reorg: remove order due to empty orderHistory", "order", tradingstate.ToJSON(order)) log.Debug("XDCx reorg: remove order due to empty orderHistory", "order", tradingstate.ToJSON(order))

View file

@ -243,7 +243,7 @@ func (XDCx *XDCX) processOrderList(coinbase common.Address, chain consensus.Chai
inversePrice := tradingStateDB.GetLastPrice(tradingstate.GetTradingOrderBookHash(common.XDCNativeAddressBinary, oldestOrder.QuoteToken)) inversePrice := tradingStateDB.GetLastPrice(tradingstate.GetTradingOrderBookHash(common.XDCNativeAddressBinary, oldestOrder.QuoteToken))
quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, oldestOrder.QuoteToken) quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, oldestOrder.QuoteToken)
if err != nil || quoteTokenDecimal.Sign() == 0 { if err != nil || quoteTokenDecimal.Sign() == 0 {
return nil, nil, nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", oldestOrder.QuoteToken.String(), err) return nil, nil, nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", oldestOrder.QuoteToken.String(), err)
} }
log.Debug("TryGet inversePrice XDC/QuoteToken", "inversePrice", inversePrice) log.Debug("TryGet inversePrice XDC/QuoteToken", "inversePrice", inversePrice)
if inversePrice != nil && inversePrice.Sign() > 0 { if inversePrice != nil && inversePrice.Sign() > 0 {
@ -368,11 +368,11 @@ func (XDCx *XDCX) processOrderList(coinbase common.Address, chain consensus.Chai
func (XDCx *XDCX) getTradeQuantity(quotePrice *big.Int, coinbase common.Address, chain consensus.ChainContext, statedb *state.StateDB, takerOrder *tradingstate.OrderItem, makerOrder *tradingstate.OrderItem, quantityToTrade *big.Int) (*big.Int, bool, *tradingstate.SettleBalance, error) { func (XDCx *XDCX) getTradeQuantity(quotePrice *big.Int, coinbase common.Address, chain consensus.ChainContext, statedb *state.StateDB, takerOrder *tradingstate.OrderItem, makerOrder *tradingstate.OrderItem, quantityToTrade *big.Int) (*big.Int, bool, *tradingstate.SettleBalance, error) {
baseTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, makerOrder.BaseToken) baseTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, makerOrder.BaseToken)
if err != nil || baseTokenDecimal.Sign() == 0 { if err != nil || baseTokenDecimal.Sign() == 0 {
return tradingstate.Zero, false, nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", makerOrder.BaseToken.String(), err) return tradingstate.Zero, false, nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", makerOrder.BaseToken.String(), err)
} }
quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, makerOrder.QuoteToken) quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, makerOrder.QuoteToken)
if err != nil || quoteTokenDecimal.Sign() == 0 { if err != nil || quoteTokenDecimal.Sign() == 0 {
return tradingstate.Zero, false, nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", makerOrder.QuoteToken.String(), err) return tradingstate.Zero, false, nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", makerOrder.QuoteToken.String(), err)
} }
if makerOrder.QuoteToken == common.XDCNativeAddressBinary { if makerOrder.QuoteToken == common.XDCNativeAddressBinary {
quotePrice = quoteTokenDecimal quotePrice = quoteTokenDecimal
@ -526,7 +526,7 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *tradingsta
matchingFee = new(big.Int).Add(matchingFee, common.RelayerFee) matchingFee = new(big.Int).Add(matchingFee, common.RelayerFee)
if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) { if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) {
return fmt.Errorf("Echange owner empty , Taker: %v , maker : %v ", takerExOwner, makerExOwner) return fmt.Errorf("empty echange owner: taker: %v , maker : %v", takerExOwner, makerExOwner)
} }
mapBalances := map[common.Address]map[common.Address]*big.Int{} mapBalances := map[common.Address]map[common.Address]*big.Int{}
//Checking balance //Checking balance
@ -656,9 +656,10 @@ func (XDCx *XDCX) ProcessCancelOrder(header *types.Header, tradingStateDB *tradi
} }
log.Debug("ProcessCancelOrder", "baseToken", originOrder.BaseToken, "quoteToken", originOrder.QuoteToken) log.Debug("ProcessCancelOrder", "baseToken", originOrder.BaseToken, "quoteToken", originOrder.QuoteToken)
feeRate := tradingstate.GetExRelayerFee(originOrder.ExchangeAddress, statedb) feeRate := tradingstate.GetExRelayerFee(originOrder.ExchangeAddress, statedb)
tokenCancelFee, tokenPriceInXDC := common.Big0, common.Big0 var tokenCancelFee, tokenPriceInXDC *big.Int
if !chain.Config().IsTIPXDCXCancellationFee(header.Number) { if !chain.Config().IsTIPXDCXCancellationFee(header.Number) {
tokenCancelFee = getCancelFeeV1(baseTokenDecimal, feeRate, &originOrder) tokenCancelFee = getCancelFeeV1(baseTokenDecimal, feeRate, &originOrder)
tokenPriceInXDC = common.Big0
} else { } else {
tokenCancelFee, tokenPriceInXDC = XDCx.getCancelFee(chain, statedb, tradingStateDB, &originOrder, feeRate) tokenCancelFee, tokenPriceInXDC = XDCx.getCancelFee(chain, statedb, tradingStateDB, &originOrder, feeRate)
} }
@ -721,7 +722,7 @@ func (XDCx *XDCX) ProcessCancelOrder(header *types.Header, tradingStateDB *tradi
// cancellation fee = 1/10 trading fee // cancellation fee = 1/10 trading fee
// deprecated after hardfork at TIPXDCXCancellationFee // deprecated after hardfork at TIPXDCXCancellationFee
func getCancelFeeV1(baseTokenDecimal *big.Int, feeRate *big.Int, order *tradingstate.OrderItem) *big.Int { func getCancelFeeV1(baseTokenDecimal *big.Int, feeRate *big.Int, order *tradingstate.OrderItem) *big.Int {
cancelFee := big.NewInt(0) var cancelFee *big.Int
if order.Side == tradingstate.Ask { if order.Side == tradingstate.Ask {
// SELL 1 BTC => XDC ,, // SELL 1 BTC => XDC ,,
// order.Quantity =1 && fee rate =2 // order.Quantity =1 && fee rate =2
@ -748,8 +749,7 @@ func (XDCx *XDCX) getCancelFee(chain consensus.ChainContext, statedb *state.Stat
if feeRate == nil || feeRate.Sign() == 0 { if feeRate == nil || feeRate.Sign() == 0 {
return common.Big0, common.Big0 return common.Big0, common.Big0
} }
cancelFee := big.NewInt(0) var cancelFee, tokenPriceInXDC *big.Int
tokenPriceInXDC := big.NewInt(0)
var err error var err error
if order.Side == tradingstate.Ask { if order.Side == tradingstate.Ask {
cancelFee, tokenPriceInXDC, err = XDCx.ConvertXDCToToken(chain, statedb, tradingStateDb, order.BaseToken, common.RelayerCancelFee) cancelFee, tokenPriceInXDC, err = XDCx.ConvertXDCToToken(chain, statedb, tradingStateDb, order.BaseToken, common.RelayerCancelFee)

View file

@ -4,15 +4,14 @@ import (
"math/big" "math/big"
"strings" "strings"
"github.com/XinFinOrg/XDPoSChain/contracts/XDCx/contract"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain" "github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts/abi" "github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/contracts/XDCx/contract"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/log"
) )
// GetTokenAbi return token abi // GetTokenAbi return token abi
@ -45,8 +44,8 @@ func RunContract(chain consensus.ChainContext, statedb *state.StateDB, contractA
} }
func (XDCx *XDCX) GetTokenDecimal(chain consensus.ChainContext, statedb *state.StateDB, tokenAddr common.Address) (*big.Int, error) { func (XDCx *XDCX) GetTokenDecimal(chain consensus.ChainContext, statedb *state.StateDB, tokenAddr common.Address) (*big.Int, error) {
if tokenDecimal, ok := XDCx.tokenDecimalCache.Get(tokenAddr); ok { if tokenDecimal, ok := XDCx.tokenDecimalCache.Get(tokenAddr); ok && tokenDecimal != nil {
return tokenDecimal.(*big.Int), nil return tokenDecimal, nil
} }
if tokenAddr == common.XDCNativeAddressBinary { if tokenAddr == common.XDCNativeAddressBinary {
XDCx.tokenDecimalCache.Add(tokenAddr, common.BasePrice) XDCx.tokenDecimalCache.Add(tokenAddr, common.BasePrice)

View file

@ -23,7 +23,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
) )
// Trie cache generation limit after which to evic trie nodes from memory. // Trie cache generation limit after which to evic trie nodes from memory.
@ -33,9 +32,6 @@ const (
// Number of past tries to keep. This value is chosen such that // Number of past tries to keep. This value is chosen such that
// reasonable chain reorg depths will hit an existing trie. // reasonable chain reorg depths will hit an existing trie.
maxPastTries = 12 maxPastTries = 12
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
) )
// Database wraps access to tries and contract code. // Database wraps access to tries and contract code.
@ -79,18 +75,15 @@ type Trie interface {
// intermediate trie-node memory pool between the low level storage layer and the // intermediate trie-node memory pool between the low level storage layer and the
// high level trie abstraction. // high level trie abstraction.
func NewDatabase(db ethdb.Database) Database { func NewDatabase(db ethdb.Database) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{ return &cachingDB{
db: trie.NewDatabase(db), db: trie.NewDatabase(db),
codeSizeCache: csc,
} }
} }
type cachingDB struct { type cachingDB struct {
db *trie.Database db *trie.Database
mu sync.Mutex mu sync.Mutex
pastTries []*XDCXTrie pastTries []*XDCXTrie
codeSizeCache *lru.Cache
} }
// OpenTrie opens the main account trie. // OpenTrie opens the main account trie.

View file

@ -47,13 +47,13 @@ type DumpOrderBookInfo struct {
LowestLiquidationPrice *big.Int LowestLiquidationPrice *big.Int
} }
func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) { func (t *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpOrderList{} mapResult := map[*big.Int]DumpOrderList{}
it := trie.NewIterator(exhangeObject.getAsksTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() { for it.Next() {
priceHash := common.BytesToHash(it.Key) priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
@ -65,15 +65,15 @@ func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]Dum
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,price :%v ", orderBook.Hex(), price) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , price :%v", orderBook.Hex(), price)
} }
stateOrderList := newStateOrderList(self, Ask, orderBook, priceHash, data, nil) stateOrderList := newStateOrderList(t, Ask, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.DumpOrderList(self.db) mapResult[price] = stateOrderList.DumpOrderList(t.db)
} }
} }
for priceHash, stateOrderList := range exhangeObject.stateAskObjects { for priceHash, stateOrderList := range exhangeObject.stateAskObjects {
if stateOrderList.Volume().Sign() > 0 { if stateOrderList.Volume().Sign() > 0 {
mapResult[new(big.Int).SetBytes(priceHash.Bytes())] = stateOrderList.DumpOrderList(self.db) mapResult[new(big.Int).SetBytes(priceHash.Bytes())] = stateOrderList.DumpOrderList(t.db)
} }
} }
listPrice := []*big.Int{} listPrice := []*big.Int{}
@ -90,13 +90,13 @@ func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]Dum
return result, nil return result, nil
} }
func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) { func (t *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpOrderList{} mapResult := map[*big.Int]DumpOrderList{}
it := trie.NewIterator(exhangeObject.getBidsTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() { for it.Next() {
priceHash := common.BytesToHash(it.Key) priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
@ -108,15 +108,15 @@ func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]Dum
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,price :%v ", orderBook.Hex(), price) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , price :%v", orderBook.Hex(), price)
} }
stateOrderList := newStateOrderList(self, Bid, orderBook, priceHash, data, nil) stateOrderList := newStateOrderList(t, Bid, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.DumpOrderList(self.db) mapResult[price] = stateOrderList.DumpOrderList(t.db)
} }
} }
for priceHash, stateOrderList := range exhangeObject.stateBidObjects { for priceHash, stateOrderList := range exhangeObject.stateBidObjects {
if stateOrderList.Volume().Sign() > 0 { if stateOrderList.Volume().Sign() > 0 {
mapResult[new(big.Int).SetBytes(priceHash.Bytes())] = stateOrderList.DumpOrderList(self.db) mapResult[new(big.Int).SetBytes(priceHash.Bytes())] = stateOrderList.DumpOrderList(t.db)
} }
} }
listPrice := []*big.Int{} listPrice := []*big.Int{}
@ -133,13 +133,13 @@ func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]Dum
return mapResult, nil return mapResult, nil
} }
func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.Int, error) { func (t *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]*big.Int{} mapResult := map[*big.Int]*big.Int{}
it := trie.NewIterator(exhangeObject.getBidsTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() { for it.Next() {
priceHash := common.BytesToHash(it.Key) priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
@ -151,9 +151,9 @@ func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.In
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,price :%v ", orderBook.Hex(), price) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , price :%v", orderBook.Hex(), price)
} }
stateOrderList := newStateOrderList(self, Bid, orderBook, priceHash, data, nil) stateOrderList := newStateOrderList(t, Bid, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.data.Volume mapResult[price] = stateOrderList.data.Volume
} }
} }
@ -176,13 +176,13 @@ func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.In
return mapResult, nil return mapResult, nil
} }
func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.Int, error) { func (t *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]*big.Int{} mapResult := map[*big.Int]*big.Int{}
it := trie.NewIterator(exhangeObject.getAsksTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() { for it.Next() {
priceHash := common.BytesToHash(it.Key) priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
@ -194,9 +194,9 @@ func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.In
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,price :%v ", orderBook.Hex(), price) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , price : %v", orderBook.Hex(), price)
} }
stateOrderList := newStateOrderList(self, Ask, orderBook, priceHash, data, nil) stateOrderList := newStateOrderList(t, Ask, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.data.Volume mapResult[price] = stateOrderList.data.Volume
} }
} }
@ -218,22 +218,23 @@ func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.In
} }
return result, nil return result, nil
} }
func (self *stateOrderList) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} func (s *stateOrderList) DumpOrderList(db Database) DumpOrderList {
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil)) mapResult := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key) keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) { if common.EmptyHash(keyHash) {
continue continue
} }
if _, exist := self.cachedStorage[keyHash]; exist { if _, exist := s.cachedStorage[keyHash]; exist {
continue continue
} else { } else {
_, content, _, _ := rlp.Split(orderListIt.Value) _, content, _, _ := rlp.Split(orderListIt.Value)
mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content) mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content)
} }
} }
for key, value := range self.cachedStorage { for key, value := range s.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes()) mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
} }
@ -245,17 +246,17 @@ func (self *stateOrderList) DumpOrderList(db Database) DumpOrderList {
sort.Slice(listIds, func(i, j int) bool { sort.Slice(listIds, func(i, j int) bool {
return listIds[i].Cmp(listIds[j]) < 0 return listIds[i].Cmp(listIds[j]) < 0
}) })
result := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} result := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
for _, id := range listIds { for _, id := range listIds {
result.Orders[id] = mapResult.Orders[id] result.Orders[id] = mapResult.Orders[id]
} }
return mapResult return mapResult
} }
func (self *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) { func (t *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
result := &DumpOrderBookInfo{} result := &DumpOrderBookInfo{}
result.LastPrice = exhangeObject.data.LastPrice result.LastPrice = exhangeObject.data.LastPrice
@ -264,29 +265,29 @@ func (self *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrder
result.MediumPriceBeforeEpoch = exhangeObject.data.MediumPriceBeforeEpoch result.MediumPriceBeforeEpoch = exhangeObject.data.MediumPriceBeforeEpoch
result.Nonce = exhangeObject.data.Nonce result.Nonce = exhangeObject.data.Nonce
result.TotalQuantity = exhangeObject.data.TotalQuantity result.TotalQuantity = exhangeObject.data.TotalQuantity
result.BestAsk = new(big.Int).SetBytes(exhangeObject.getBestPriceAsksTrie(self.db).Bytes()) result.BestAsk = new(big.Int).SetBytes(exhangeObject.getBestPriceAsksTrie(t.db).Bytes())
result.BestBid = new(big.Int).SetBytes(exhangeObject.getBestBidsTrie(self.db).Bytes()) result.BestBid = new(big.Int).SetBytes(exhangeObject.getBestBidsTrie(t.db).Bytes())
lowestPrice, _ := exhangeObject.getLowestLiquidationPrice(self.db) lowestPrice, _ := exhangeObject.getLowestLiquidationPrice(t.db)
result.LowestLiquidationPrice = new(big.Int).SetBytes(lowestPrice.Bytes()) result.LowestLiquidationPrice = new(big.Int).SetBytes(lowestPrice.Bytes())
return result, nil return result, nil
} }
func (self *stateLendingBook) DumpOrderList(db Database) DumpOrderList { func (s *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} mapResult := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil)) orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key) keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) { if common.EmptyHash(keyHash) {
continue continue
} }
if _, exist := self.cachedStorage[keyHash]; exist { if _, exist := s.cachedStorage[keyHash]; exist {
continue continue
} else { } else {
_, content, _, _ := rlp.Split(orderListIt.Value) _, content, _, _ := rlp.Split(orderListIt.Value)
mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content) mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content)
} }
} }
for key, value := range self.cachedStorage { for key, value := range s.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes()) mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
} }
@ -298,33 +299,33 @@ func (self *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
sort.Slice(listIds, func(i, j int) bool { sort.Slice(listIds, func(i, j int) bool {
return listIds[i].Cmp(listIds[j]) < 0 return listIds[i].Cmp(listIds[j]) < 0
}) })
result := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} result := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
for _, id := range listIds { for _, id := range listIds {
result.Orders[id] = mapResult.Orders[id] result.Orders[id] = mapResult.Orders[id]
} }
return mapResult return mapResult
} }
func (self *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, error) { func (l *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, error) {
result := DumpLendingBook{Volume: self.Volume(), LendingBooks: map[common.Hash]DumpOrderList{}} result := DumpLendingBook{Volume: l.Volume(), LendingBooks: map[common.Hash]DumpOrderList{}}
it := trie.NewIterator(self.getTrie(db).NodeIterator(nil)) it := trie.NewIterator(l.getTrie(db).NodeIterator(nil))
for it.Next() { for it.Next() {
lendingBook := common.BytesToHash(it.Key) lendingBook := common.BytesToHash(it.Key)
if common.EmptyHash(lendingBook) { if common.EmptyHash(lendingBook) {
continue continue
} }
if _, exist := self.stateLendingBooks[lendingBook]; exist { if _, exist := l.stateLendingBooks[lendingBook]; exist {
continue continue
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return result, fmt.Errorf("Failed to decode state lending book orderbook : %s ,liquidation price :%s , lendingBook : %s ,err : %v", self.orderBook, self.liquidationPrice, lendingBook, err) return result, fmt.Errorf("failed to decode state lending book orderbook: %s, liquidation price: %s , lendingBook: %s , err: %v", l.orderBook, l.liquidationPrice, lendingBook, err)
} }
stateLendingBook := newStateLendingBook(self.orderBook, self.liquidationPrice, lendingBook, data, nil) stateLendingBook := newStateLendingBook(l.orderBook, l.liquidationPrice, lendingBook, data, nil)
result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db) result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db)
} }
} }
for lendingBook, stateLendingBook := range self.stateLendingBooks { for lendingBook, stateLendingBook := range l.stateLendingBooks {
if !common.EmptyHash(lendingBook) { if !common.EmptyHash(lendingBook) {
result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db) result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db)
} }
@ -332,13 +333,13 @@ func (self *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook
return result, nil return result, nil
} }
func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map[*big.Int]DumpLendingBook, error) { func (t *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map[*big.Int]DumpLendingBook, error) {
exhangeObject := self.getStateExchangeObject(orderBook) exhangeObject := t.getStateExchangeObject(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpLendingBook{} mapResult := map[*big.Int]DumpLendingBook{}
it := trie.NewIterator(exhangeObject.getLiquidationPriceTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getLiquidationPriceTrie(t.db).NodeIterator(nil))
for it.Next() { for it.Next() {
priceHash := common.BytesToHash(it.Key) priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
@ -350,10 +351,10 @@ func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map
} else { } else {
var data orderList var data orderList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,price :%v ", orderBook.Hex(), price) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , price : %v", orderBook.Hex(), price)
} }
liquidationPriceState := newLiquidationPriceState(self, orderBook, priceHash, data, nil) liquidationPriceState := newLiquidationPriceState(t, orderBook, priceHash, data, nil)
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(self.db) dumpLendingBook, err := liquidationPriceState.DumpLendingBook(t.db)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -362,7 +363,7 @@ func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map
} }
for priceHash, liquidationPriceState := range exhangeObject.liquidationPriceStates { for priceHash, liquidationPriceState := range exhangeObject.liquidationPriceStates {
if liquidationPriceState.Volume().Sign() > 0 { if liquidationPriceState.Volume().Sign() > 0 {
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(self.db) dumpLendingBook, err := liquidationPriceState.DumpLendingBook(t.db)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -106,7 +106,7 @@ func GetAllTradingPairs(statedb *state.StateDB) (map[common.Hash]bool, error) {
toTokenSlot := new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"]) toTokenSlot := new(big.Int).Add(locBig, RelayerStructMappingSlot["_toTokens"])
toTokenLength := statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), common.BigToHash(toTokenSlot)).Big().Uint64() toTokenLength := statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), common.BigToHash(toTokenSlot)).Big().Uint64()
if toTokenLength != fromTokenLength { if toTokenLength != fromTokenLength {
return map[common.Hash]bool{}, fmt.Errorf("Invalid length from token & to toke : from :%d , to :%d ", fromTokenLength, toTokenLength) return map[common.Hash]bool{}, fmt.Errorf("invalid length from token & to token: from :%d , to :%d ", fromTokenLength, toTokenLength)
} }
fromTokens := []common.Address{} fromTokens := []common.Address{}
fromTokenSlotHash := common.BytesToHash(fromTokenSlot.Bytes()) fromTokenSlotHash := common.BytesToHash(fromTokenSlot.Bytes())
@ -279,7 +279,7 @@ func CheckAddTokenBalance(addr common.Address, value *big.Int, token common.Addr
newBalance := new(big.Int).Add(balance, value) newBalance := new(big.Int).Add(balance, value)
log.Debug("CheckAddTokenBalance settle balance: ADD TOKEN BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance) log.Debug("CheckAddTokenBalance settle balance: ADD TOKEN BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
if common.BigToHash(newBalance).Big().Cmp(newBalance) != 0 { if common.BigToHash(newBalance).Big().Cmp(newBalance) != 0 {
return nil, fmt.Errorf("Overflow when try add token balance , max is 2^256 , balance : %v , value:%v ", balance, value) return nil, fmt.Errorf("overflow when try add token balance , max is 2^256 , balance : %v , value : %v", balance, value)
} else { } else {
return newBalance, nil return newBalance, nil
} }

View file

@ -65,59 +65,59 @@ func newStateLendingBook(orderBook common.Hash, price common.Hash, lendingBook c
} }
} }
func (self *stateLendingBook) EncodeRLP(w io.Writer) error { func (s *stateLendingBook) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, self.data) return rlp.Encode(w, s.data)
} }
func (self *stateLendingBook) setError(err error) { func (s *stateLendingBook) setError(err error) {
if self.dbErr == nil { if s.dbErr == nil {
self.dbErr = err s.dbErr = err
} }
} }
func (self *stateLendingBook) getTrie(db Database) Trie { func (s *stateLendingBook) getTrie(db Database) Trie {
if self.trie == nil { if s.trie == nil {
var err error var err error
self.trie, err = db.OpenStorageTrie(self.lendingBook, self.data.Root) s.trie, err = db.OpenStorageTrie(s.lendingBook, s.data.Root)
if err != nil { if err != nil {
self.trie, _ = db.OpenStorageTrie(self.price, EmptyHash) s.trie, _ = db.OpenStorageTrie(s.price, EmptyHash)
self.setError(fmt.Errorf("can't create storage trie: %v", err)) s.setError(fmt.Errorf("can't create storage trie: %v", err))
} }
} }
return self.trie return s.trie
} }
func (self *stateLendingBook) Exist(db Database, lendingId common.Hash) bool { func (s *stateLendingBook) Exist(db Database, lendingId common.Hash) bool {
amount, exists := self.cachedStorage[lendingId] amount, exists := s.cachedStorage[lendingId]
if exists { if exists {
return true return true
} }
// Load from DB in case it is missing. // Load from DB in case it is missing.
enc, err := self.getTrie(db).TryGet(lendingId[:]) enc, err := s.getTrie(db).TryGet(lendingId[:])
if err != nil { if err != nil {
self.setError(err) s.setError(err)
return false return false
} }
if len(enc) > 0 { if len(enc) > 0 {
_, content, _, err := rlp.Split(enc) _, content, _, err := rlp.Split(enc)
if err != nil { if err != nil {
self.setError(err) s.setError(err)
} }
amount.SetBytes(content) amount.SetBytes(content)
} }
if (amount != common.Hash{}) { if (amount != common.Hash{}) {
self.cachedStorage[lendingId] = amount s.cachedStorage[lendingId] = amount
} }
return true return true
} }
func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash { func (s *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
tradeIds := []common.Hash{} tradeIds := []common.Hash{}
lendingBookTrie := self.getTrie(db) lendingBookTrie := s.getTrie(db)
if lendingBookTrie == nil { if lendingBookTrie == nil {
return tradeIds return tradeIds
} }
for id, value := range self.cachedStorage { for id, value := range s.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
tradeIds = append(tradeIds, id) tradeIds = append(tradeIds, id)
} }
@ -125,7 +125,7 @@ func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil)) orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
id := common.BytesToHash(orderListIt.Key) id := common.BytesToHash(orderListIt.Key)
if _, exist := self.cachedStorage[id]; exist { if _, exist := s.cachedStorage[id]; exist {
continue continue
} }
tradeIds = append(tradeIds, id) tradeIds = append(tradeIds, id)
@ -133,83 +133,83 @@ func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
return tradeIds return tradeIds
} }
func (self *stateLendingBook) insertTradingId(db Database, tradeId common.Hash) { func (s *stateLendingBook) insertTradingId(db Database, tradeId common.Hash) {
self.setTradingId(tradeId, tradeId) s.setTradingId(tradeId, tradeId)
self.setError(self.getTrie(db).TryUpdate(tradeId[:], tradeId[:])) s.setError(s.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
} }
func (self *stateLendingBook) removeTradingId(db Database, tradeId common.Hash) { func (s *stateLendingBook) removeTradingId(db Database, tradeId common.Hash) {
tr := self.getTrie(db) tr := s.getTrie(db)
self.setError(tr.TryDelete(tradeId[:])) s.setError(tr.TryDelete(tradeId[:]))
self.setTradingId(tradeId, EmptyHash) s.setTradingId(tradeId, EmptyHash)
} }
func (self *stateLendingBook) setTradingId(tradeId common.Hash, value common.Hash) { func (s *stateLendingBook) setTradingId(tradeId common.Hash, value common.Hash) {
self.cachedStorage[tradeId] = value s.cachedStorage[tradeId] = value
self.dirtyStorage[tradeId] = value s.dirtyStorage[tradeId] = value
if self.onDirty != nil { if s.onDirty != nil {
self.onDirty(self.lendingBook) s.onDirty(s.lendingBook)
self.onDirty = nil s.onDirty = nil
} }
} }
func (self *stateLendingBook) updateTrie(db Database) Trie { func (s *stateLendingBook) updateTrie(db Database) Trie {
tr := self.getTrie(db) tr := s.getTrie(db)
for key, value := range self.dirtyStorage { for key, value := range s.dirtyStorage {
delete(self.dirtyStorage, key) delete(s.dirtyStorage, key)
if value == EmptyHash { if value == EmptyHash {
self.setError(tr.TryDelete(key[:])) s.setError(tr.TryDelete(key[:]))
continue continue
} }
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
self.setError(tr.TryUpdate(key[:], v)) s.setError(tr.TryUpdate(key[:], v))
} }
return tr return tr
} }
func (self *stateLendingBook) updateRoot(db Database) error { func (s *stateLendingBook) updateRoot(db Database) error {
self.updateTrie(db) s.updateTrie(db)
if self.dbErr != nil { if s.dbErr != nil {
return self.dbErr return s.dbErr
} }
root, err := self.trie.Commit(nil) root, err := s.trie.Commit(nil)
if err == nil { if err == nil {
self.data.Root = root s.data.Root = root
} }
return err return err
} }
func (self *stateLendingBook) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateLendingBook { func (s *stateLendingBook) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateLendingBook {
stateLendingBook := newStateLendingBook(self.lendingBook, self.orderBook, self.price, self.data, onDirty) stateLendingBook := newStateLendingBook(s.lendingBook, s.orderBook, s.price, s.data, onDirty)
if self.trie != nil { if s.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(self.trie) stateLendingBook.trie = db.db.CopyTrie(s.trie)
} }
for key, value := range self.dirtyStorage { for key, value := range s.dirtyStorage {
stateLendingBook.dirtyStorage[key] = value stateLendingBook.dirtyStorage[key] = value
} }
for key, value := range self.cachedStorage { for key, value := range s.cachedStorage {
stateLendingBook.cachedStorage[key] = value stateLendingBook.cachedStorage[key] = value
} }
return stateLendingBook return stateLendingBook
} }
func (c *stateLendingBook) AddVolume(amount *big.Int) { func (s *stateLendingBook) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount)) s.setVolume(new(big.Int).Add(s.data.Volume, amount))
} }
func (c *stateLendingBook) subVolume(amount *big.Int) { func (s *stateLendingBook) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount)) s.setVolume(new(big.Int).Sub(s.data.Volume, amount))
} }
func (self *stateLendingBook) setVolume(volume *big.Int) { func (s *stateLendingBook) setVolume(volume *big.Int) {
self.data.Volume = volume s.data.Volume = volume
if self.onDirty != nil { if s.onDirty != nil {
self.onDirty(self.lendingBook) s.onDirty(s.lendingBook)
self.onDirty = nil s.onDirty = nil
} }
} }
func (self *stateLendingBook) Volume() *big.Int { func (s *stateLendingBook) Volume() *big.Int {
return self.data.Volume return s.data.Volume
} }

View file

@ -68,54 +68,54 @@ func newLiquidationPriceState(db *TradingStateDB, orderBook common.Hash, price c
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *liquidationPriceState) EncodeRLP(w io.Writer) error { func (l *liquidationPriceState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, l.data)
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *liquidationPriceState) setError(err error) { func (l *liquidationPriceState) setError(err error) {
if self.dbErr == nil { if l.dbErr == nil {
self.dbErr = err l.dbErr = err
} }
} }
func (self *liquidationPriceState) MarkStateLendingBookDirty(price common.Hash) { func (l *liquidationPriceState) MarkStateLendingBookDirty(price common.Hash) {
self.stateLendingBooksDirty[price] = struct{}{} l.stateLendingBooksDirty[price] = struct{}{}
if self.onDirty != nil { if l.onDirty != nil {
self.onDirty(self.liquidationPrice) l.onDirty(l.liquidationPrice)
self.onDirty = nil l.onDirty = nil
} }
} }
func (self *liquidationPriceState) createLendingBook(db Database, lendingBook common.Hash) (newobj *stateLendingBook) { func (l *liquidationPriceState) createLendingBook(db Database, lendingBook common.Hash) (newobj *stateLendingBook) {
newobj = newStateLendingBook(self.orderBook, self.liquidationPrice, lendingBook, orderList{Volume: Zero}, self.MarkStateLendingBookDirty) newobj = newStateLendingBook(l.orderBook, l.liquidationPrice, lendingBook, orderList{Volume: Zero}, l.MarkStateLendingBookDirty)
self.stateLendingBooks[lendingBook] = newobj l.stateLendingBooks[lendingBook] = newobj
self.stateLendingBooksDirty[lendingBook] = struct{}{} l.stateLendingBooksDirty[lendingBook] = struct{}{}
if self.onDirty != nil { if l.onDirty != nil {
self.onDirty(self.liquidationPrice) l.onDirty(l.liquidationPrice)
self.onDirty = nil l.onDirty = nil
} }
return newobj return newobj
} }
func (self *liquidationPriceState) getTrie(db Database) Trie { func (l *liquidationPriceState) getTrie(db Database) Trie {
if self.trie == nil { if l.trie == nil {
var err error var err error
self.trie, err = db.OpenStorageTrie(self.liquidationPrice, self.data.Root) l.trie, err = db.OpenStorageTrie(l.liquidationPrice, l.data.Root)
if err != nil { if err != nil {
self.trie, _ = db.OpenStorageTrie(self.liquidationPrice, EmptyHash) l.trie, _ = db.OpenStorageTrie(l.liquidationPrice, EmptyHash)
self.setError(fmt.Errorf("can't create storage trie: %v", err)) l.setError(fmt.Errorf("can't create storage trie: %v", err))
} }
} }
return self.trie return l.trie
} }
func (self *liquidationPriceState) updateTrie(db Database) Trie { func (l *liquidationPriceState) updateTrie(db Database) Trie {
tr := self.getTrie(db) tr := l.getTrie(db)
for lendingId, stateObject := range self.stateLendingBooks { for lendingId, stateObject := range l.stateLendingBooks {
delete(self.stateLendingBooksDirty, lendingId) delete(l.stateLendingBooksDirty, lendingId)
if stateObject.empty() { if stateObject.empty() {
self.setError(tr.TryDelete(lendingId[:])) l.setError(tr.TryDelete(lendingId[:]))
continue continue
} }
err := stateObject.updateRoot(db) err := stateObject.updateRoot(db)
@ -125,17 +125,17 @@ func (self *liquidationPriceState) updateTrie(db Database) Trie {
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(stateObject) v, _ := rlp.EncodeToBytes(stateObject)
self.setError(tr.TryUpdate(lendingId[:], v)) l.setError(tr.TryUpdate(lendingId[:], v))
} }
return tr return tr
} }
func (self *liquidationPriceState) updateRoot(db Database) error { func (l *liquidationPriceState) updateRoot(db Database) error {
self.updateTrie(db) l.updateTrie(db)
if self.dbErr != nil { if l.dbErr != nil {
return self.dbErr return l.dbErr
} }
root, err := self.trie.Commit(func(leaf []byte, parent common.Hash) error { root, err := l.trie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList orderList var orderList orderList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -146,57 +146,57 @@ func (self *liquidationPriceState) updateRoot(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.Root = root l.data.Root = root
} }
return err return err
} }
func (self *liquidationPriceState) deepCopy(db *TradingStateDB, onDirty func(liquidationPrice common.Hash)) *liquidationPriceState { func (l *liquidationPriceState) deepCopy(db *TradingStateDB, onDirty func(liquidationPrice common.Hash)) *liquidationPriceState {
stateOrderList := newLiquidationPriceState(db, self.orderBook, self.liquidationPrice, self.data, onDirty) stateOrderList := newLiquidationPriceState(db, l.orderBook, l.liquidationPrice, l.data, onDirty)
if self.trie != nil { if l.trie != nil {
stateOrderList.trie = db.db.CopyTrie(self.trie) stateOrderList.trie = db.db.CopyTrie(l.trie)
} }
for key, value := range self.stateLendingBooks { for key, value := range l.stateLendingBooks {
stateOrderList.stateLendingBooks[key] = value.deepCopy(db, self.MarkStateLendingBookDirty) stateOrderList.stateLendingBooks[key] = value.deepCopy(db, l.MarkStateLendingBookDirty)
} }
for key, value := range self.stateLendingBooksDirty { for key, value := range l.stateLendingBooksDirty {
stateOrderList.stateLendingBooksDirty[key] = value stateOrderList.stateLendingBooksDirty[key] = value
} }
return stateOrderList return stateOrderList
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *liquidationPriceState) getStateLendingBook(db Database, lendingBook common.Hash) (stateObject *stateLendingBook) { func (l *liquidationPriceState) getStateLendingBook(db Database, lendingBook common.Hash) (stateObject *stateLendingBook) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.stateLendingBooks[lendingBook]; obj != nil { if obj := l.stateLendingBooks[lendingBook]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getTrie(db).TryGet(lendingBook[:]) enc, err := l.getTrie(db).TryGet(lendingBook[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) l.setError(err)
return nil return nil
} }
var data orderList var data orderList
if err := rlp.DecodeBytes(enc, &data); err != nil { if err := rlp.DecodeBytes(enc, &data); err != nil {
log.Error("Failed to decode state lending book ", "orderbook", self.orderBook, "liquidation price", self.liquidationPrice, "lendingBook", lendingBook, "err", err) log.Error("Failed to decode state lending book ", "orderbook", l.orderBook, "liquidation price", l.liquidationPrice, "lendingBook", lendingBook, "err", err)
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateLendingBook(self.orderBook, self.liquidationPrice, lendingBook, data, self.MarkStateLendingBookDirty) obj := newStateLendingBook(l.orderBook, l.liquidationPrice, lendingBook, data, l.MarkStateLendingBookDirty)
self.stateLendingBooks[lendingBook] = obj l.stateLendingBooks[lendingBook] = obj
return obj return obj
} }
func (self *liquidationPriceState) getAllLiquidationData(db Database) map[common.Hash][]common.Hash { func (l *liquidationPriceState) getAllLiquidationData(db Database) map[common.Hash][]common.Hash {
liquidationData := map[common.Hash][]common.Hash{} liquidationData := map[common.Hash][]common.Hash{}
lendingBookTrie := self.getTrie(db) lendingBookTrie := l.getTrie(db)
if lendingBookTrie == nil { if lendingBookTrie == nil {
return liquidationData return liquidationData
} }
lendingBooks := []common.Hash{} lendingBooks := []common.Hash{}
for id, stateLendingBook := range self.stateLendingBooks { for id, stateLendingBook := range l.stateLendingBooks {
if !stateLendingBook.empty() { if !stateLendingBook.empty() {
lendingBooks = append(lendingBooks, id) lendingBooks = append(lendingBooks, id)
} }
@ -204,13 +204,13 @@ func (self *liquidationPriceState) getAllLiquidationData(db Database) map[common
lendingBookListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil)) lendingBookListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil))
for lendingBookListIt.Next() { for lendingBookListIt.Next() {
id := common.BytesToHash(lendingBookListIt.Key) id := common.BytesToHash(lendingBookListIt.Key)
if _, exist := self.stateLendingBooks[id]; exist { if _, exist := l.stateLendingBooks[id]; exist {
continue continue
} }
lendingBooks = append(lendingBooks, id) lendingBooks = append(lendingBooks, id)
} }
for _, lendingBook := range lendingBooks { for _, lendingBook := range lendingBooks {
stateLendingBook := self.getStateLendingBook(db, lendingBook) stateLendingBook := l.getStateLendingBook(db, lendingBook)
if stateLendingBook != nil { if stateLendingBook != nil {
liquidationData[lendingBook] = stateLendingBook.getAllTradeIds(db) liquidationData[lendingBook] = stateLendingBook.getAllTradeIds(db)
} }
@ -218,22 +218,22 @@ func (self *liquidationPriceState) getAllLiquidationData(db Database) map[common
return liquidationData return liquidationData
} }
func (c *liquidationPriceState) AddVolume(amount *big.Int) { func (l *liquidationPriceState) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount)) l.setVolume(new(big.Int).Add(l.data.Volume, amount))
} }
func (c *liquidationPriceState) subVolume(amount *big.Int) { func (c *liquidationPriceState) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount)) c.setVolume(new(big.Int).Sub(c.data.Volume, amount))
} }
func (self *liquidationPriceState) setVolume(volume *big.Int) { func (l *liquidationPriceState) setVolume(volume *big.Int) {
self.data.Volume = volume l.data.Volume = volume
if self.onDirty != nil { if l.onDirty != nil {
self.onDirty(self.liquidationPrice) l.onDirty(l.liquidationPrice)
self.onDirty = nil l.onDirty = nil
} }
} }
func (self *liquidationPriceState) Volume() *big.Int { func (l *liquidationPriceState) Volume() *big.Int {
return self.data.Volume return l.data.Volume
} }

View file

@ -53,23 +53,23 @@ func newStateOrderItem(orderBook common.Hash, orderId common.Hash, data OrderIte
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *stateOrderItem) EncodeRLP(w io.Writer) error { func (s *stateOrderItem) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, s.data)
} }
func (self *stateOrderItem) deepCopy(onDirty func(orderId common.Hash)) *stateOrderItem { func (s *stateOrderItem) deepCopy(onDirty func(orderId common.Hash)) *stateOrderItem {
stateOrderList := newStateOrderItem(self.orderBook, self.orderId, self.data, onDirty) stateOrderList := newStateOrderItem(s.orderBook, s.orderId, s.data, onDirty)
return stateOrderList return stateOrderList
} }
func (self *stateOrderItem) setVolume(volume *big.Int) { func (s *stateOrderItem) setVolume(volume *big.Int) {
self.data.Quantity = volume s.data.Quantity = volume
if self.onDirty != nil { if s.onDirty != nil {
self.onDirty(self.orderId) s.onDirty(s.orderId)
self.onDirty = nil s.onDirty = nil
} }
} }
func (self *stateOrderItem) Quantity() *big.Int { func (s *stateOrderItem) Quantity() *big.Int {
return self.data.Quantity return s.data.Quantity
} }

View file

@ -75,14 +75,14 @@ func newStateOrderList(db *TradingStateDB, orderType string, orderBook common.Ha
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *stateOrderList) EncodeRLP(w io.Writer) error { func (s *stateOrderList) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, s.data)
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *stateOrderList) setError(err error) { func (s *stateOrderList) setError(err error) {
if self.dbErr == nil { if s.dbErr == nil {
self.dbErr = err s.dbErr = err
} }
} }
@ -99,90 +99,90 @@ func (c *stateOrderList) getTrie(db Database) Trie {
} }
// GetState returns a value in orderId storage. // GetState returns a value in orderId storage.
func (self *stateOrderList) GetOrderAmount(db Database, orderId common.Hash) common.Hash { func (s *stateOrderList) GetOrderAmount(db Database, orderId common.Hash) common.Hash {
amount, exists := self.cachedStorage[orderId] amount, exists := s.cachedStorage[orderId]
if exists { if exists {
return amount return amount
} }
// Load from DB in case it is missing. // Load from DB in case it is missing.
enc, err := self.getTrie(db).TryGet(orderId[:]) enc, err := s.getTrie(db).TryGet(orderId[:])
if err != nil { if err != nil {
self.setError(err) s.setError(err)
return EmptyHash return EmptyHash
} }
if len(enc) > 0 { if len(enc) > 0 {
_, content, _, err := rlp.Split(enc) _, content, _, err := rlp.Split(enc)
if err != nil { if err != nil {
self.setError(err) s.setError(err)
} }
amount.SetBytes(content) amount.SetBytes(content)
} }
if (amount != common.Hash{}) { if (amount != common.Hash{}) {
self.cachedStorage[orderId] = amount s.cachedStorage[orderId] = amount
} }
return amount return amount
} }
// SetState updates a value in orderId storage. // SetState updates a value in orderId storage.
func (self *stateOrderList) insertOrderItem(db Database, orderId common.Hash, amount common.Hash) { func (s *stateOrderList) insertOrderItem(db Database, orderId common.Hash, amount common.Hash) {
self.setOrderItem(orderId, amount) s.setOrderItem(orderId, amount)
self.setError(self.getTrie(db).TryUpdate(orderId[:], amount[:])) s.setError(s.getTrie(db).TryUpdate(orderId[:], amount[:]))
} }
// SetState updates a value in orderId storage. // SetState updates a value in orderId storage.
func (self *stateOrderList) removeOrderItem(db Database, orderId common.Hash) { func (s *stateOrderList) removeOrderItem(db Database, orderId common.Hash) {
tr := self.getTrie(db) tr := s.getTrie(db)
self.setError(tr.TryDelete(orderId[:])) s.setError(tr.TryDelete(orderId[:]))
self.setOrderItem(orderId, EmptyHash) s.setOrderItem(orderId, EmptyHash)
} }
func (self *stateOrderList) setOrderItem(orderId common.Hash, amount common.Hash) { func (s *stateOrderList) setOrderItem(orderId common.Hash, amount common.Hash) {
self.cachedStorage[orderId] = amount s.cachedStorage[orderId] = amount
self.dirtyStorage[orderId] = amount s.dirtyStorage[orderId] = amount
if self.onDirty != nil { if s.onDirty != nil {
self.onDirty(self.Price()) s.onDirty(s.Price())
self.onDirty = nil s.onDirty = nil
} }
} }
// updateAskTrie writes cached storage modifications into the object's storage trie. // updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *stateOrderList) updateTrie(db Database) Trie { func (s *stateOrderList) updateTrie(db Database) Trie {
tr := self.getTrie(db) tr := s.getTrie(db)
for orderId, amount := range self.dirtyStorage { for orderId, amount := range s.dirtyStorage {
delete(self.dirtyStorage, orderId) delete(s.dirtyStorage, orderId)
if amount == EmptyHash { if amount == EmptyHash {
self.setError(tr.TryDelete(orderId[:])) s.setError(tr.TryDelete(orderId[:]))
continue continue
} }
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(amount[:], "\x00")) v, _ := rlp.EncodeToBytes(bytes.TrimLeft(amount[:], "\x00"))
self.setError(tr.TryUpdate(orderId[:], v)) s.setError(tr.TryUpdate(orderId[:], v))
} }
return tr return tr
} }
// UpdateRoot sets the trie root to the current root orderId of // UpdateRoot sets the trie root to the current root orderId of
func (self *stateOrderList) updateRoot(db Database) error { func (s *stateOrderList) updateRoot(db Database) error {
self.updateTrie(db) s.updateTrie(db)
if self.dbErr != nil { if s.dbErr != nil {
return self.dbErr return s.dbErr
} }
root, err := self.trie.Commit(nil) root, err := s.trie.Commit(nil)
if err == nil { if err == nil {
self.data.Root = root s.data.Root = root
} }
return err return err
} }
func (self *stateOrderList) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateOrderList { func (s *stateOrderList) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateOrderList {
stateOrderList := newStateOrderList(db, self.orderType, self.orderBook, self.price, self.data, onDirty) stateOrderList := newStateOrderList(db, s.orderType, s.orderBook, s.price, s.data, onDirty)
if self.trie != nil { if s.trie != nil {
stateOrderList.trie = db.db.CopyTrie(self.trie) stateOrderList.trie = db.db.CopyTrie(s.trie)
} }
for orderId, amount := range self.dirtyStorage { for orderId, amount := range s.dirtyStorage {
stateOrderList.dirtyStorage[orderId] = amount stateOrderList.dirtyStorage[orderId] = amount
} }
for orderId, amount := range self.cachedStorage { for orderId, amount := range s.cachedStorage {
stateOrderList.cachedStorage[orderId] = amount stateOrderList.cachedStorage[orderId] = amount
} }
return stateOrderList return stateOrderList
@ -190,29 +190,29 @@ func (self *stateOrderList) deepCopy(db *TradingStateDB, onDirty func(price comm
// AddVolume removes amount from c's balance. // AddVolume removes amount from c's balance.
// It is used to add funds to the destination exchanges of a transfer. // It is used to add funds to the destination exchanges of a transfer.
func (c *stateOrderList) AddVolume(amount *big.Int) { func (s *stateOrderList) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount)) s.setVolume(new(big.Int).Add(s.data.Volume, amount))
} }
// AddVolume removes amount from c's balance. // AddVolume removes amount from c's balance.
// It is used to add funds to the destination exchanges of a transfer. // It is used to add funds to the destination exchanges of a transfer.
func (c *stateOrderList) subVolume(amount *big.Int) { func (s *stateOrderList) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount)) s.setVolume(new(big.Int).Sub(s.data.Volume, amount))
} }
func (self *stateOrderList) setVolume(volume *big.Int) { func (s *stateOrderList) setVolume(volume *big.Int) {
self.data.Volume = volume s.data.Volume = volume
if self.onDirty != nil { if s.onDirty != nil {
self.onDirty(self.price) s.onDirty(s.price)
self.onDirty = nil s.onDirty = nil
} }
} }
// Returns the address of the contract/orderId // Returns the address of the contract/orderId
func (c *stateOrderList) Price() common.Hash { func (s *stateOrderList) Price() common.Hash {
return c.price return s.price
} }
func (self *stateOrderList) Volume() *big.Int { func (s *stateOrderList) Volume() *big.Int {
return self.data.Volume return s.data.Volume
} }

View file

@ -66,35 +66,35 @@ type tradingExchanges struct {
} }
// empty returns whether the orderId is considered empty. // empty returns whether the orderId is considered empty.
func (s *tradingExchanges) empty() bool { func (te *tradingExchanges) empty() bool {
if s.data.Nonce != 0 { if te.data.Nonce != 0 {
return false return false
} }
if s.data.LendingCount != nil && s.data.LendingCount.Sign() > 0 { if te.data.LendingCount != nil && te.data.LendingCount.Sign() > 0 {
return false return false
} }
if s.data.LastPrice != nil && s.data.LastPrice.Sign() > 0 { if te.data.LastPrice != nil && te.data.LastPrice.Sign() > 0 {
return false return false
} }
if s.data.MediumPrice != nil && s.data.MediumPrice.Sign() > 0 { if te.data.MediumPrice != nil && te.data.MediumPrice.Sign() > 0 {
return false return false
} }
if s.data.MediumPriceBeforeEpoch != nil && s.data.MediumPriceBeforeEpoch.Sign() > 0 { if te.data.MediumPriceBeforeEpoch != nil && te.data.MediumPriceBeforeEpoch.Sign() > 0 {
return false return false
} }
if s.data.TotalQuantity != nil && s.data.TotalQuantity.Sign() > 0 { if te.data.TotalQuantity != nil && te.data.TotalQuantity.Sign() > 0 {
return false return false
} }
if !common.EmptyHash(s.data.AskRoot) { if !common.EmptyHash(te.data.AskRoot) {
return false return false
} }
if !common.EmptyHash(s.data.BidRoot) { if !common.EmptyHash(te.data.BidRoot) {
return false return false
} }
if !common.EmptyHash(s.data.OrderRoot) { if !common.EmptyHash(te.data.OrderRoot) {
return false return false
} }
if !common.EmptyHash(s.data.LiquidationPriceRoot) { if !common.EmptyHash(te.data.LiquidationPriceRoot) {
return false return false
} }
return true return true
@ -119,46 +119,46 @@ func newStateExchanges(db *TradingStateDB, hash common.Hash, data tradingExchang
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *tradingExchanges) EncodeRLP(w io.Writer) error { func (te *tradingExchanges) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, te.data)
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *tradingExchanges) setError(err error) { func (te *tradingExchanges) setError(err error) {
if self.dbErr == nil { if te.dbErr == nil {
self.dbErr = err te.dbErr = err
} }
} }
func (c *tradingExchanges) getAsksTrie(db Database) Trie { func (te *tradingExchanges) getAsksTrie(db Database) Trie {
if c.asksTrie == nil { if te.asksTrie == nil {
var err error var err error
c.asksTrie, err = db.OpenStorageTrie(c.orderBookHash, c.data.AskRoot) te.asksTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.AskRoot)
if err != nil { if err != nil {
c.asksTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash) te.asksTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create asks trie: %v", err)) te.setError(fmt.Errorf("can't create asks trie: %v", err))
} }
} }
return c.asksTrie return te.asksTrie
} }
func (c *tradingExchanges) getOrdersTrie(db Database) Trie { func (te *tradingExchanges) getOrdersTrie(db Database) Trie {
if c.ordersTrie == nil { if te.ordersTrie == nil {
var err error var err error
c.ordersTrie, err = db.OpenStorageTrie(c.orderBookHash, c.data.OrderRoot) te.ordersTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.OrderRoot)
if err != nil { if err != nil {
c.ordersTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash) te.ordersTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create asks trie: %v", err)) te.setError(fmt.Errorf("can't create asks trie: %v", err))
} }
} }
return c.ordersTrie return te.ordersTrie
} }
func (c *tradingExchanges) getBestPriceAsksTrie(db Database) common.Hash { func (te *tradingExchanges) getBestPriceAsksTrie(db Database) common.Hash {
trie := c.getAsksTrie(db) trie := te.getAsksTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue() encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best price ask trie ", "orderbook", c.orderBookHash.Hex()) log.Error("Failed find best price ask trie ", "orderbook", te.orderBookHash.Hex())
return EmptyHash return EmptyHash
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -166,23 +166,23 @@ func (c *tradingExchanges) getBestPriceAsksTrie(db Database) common.Hash {
return EmptyHash return EmptyHash
} }
price := common.BytesToHash(encKey) price := common.BytesToHash(encKey)
if _, exit := c.stateAskObjects[price]; !exit { if _, exit := te.stateAskObjects[price]; !exit {
var data orderList var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err) log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash return EmptyHash
} }
obj := newStateOrderList(c.db, Bid, c.orderBookHash, price, data, c.MarkStateAskObjectDirty) obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateAskObjectDirty)
c.stateAskObjects[price] = obj te.stateAskObjects[price] = obj
} }
return common.BytesToHash(encKey) return common.BytesToHash(encKey)
} }
func (c *tradingExchanges) getBestBidsTrie(db Database) common.Hash { func (te *tradingExchanges) getBestBidsTrie(db Database) common.Hash {
trie := c.getBidsTrie(db) trie := te.getBidsTrie(db)
encKey, encValue, err := trie.TryGetBestRightKeyAndValue() encKey, encValue, err := trie.TryGetBestRightKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best price bid trie ", "orderbook", c.orderBookHash.Hex()) log.Error("Failed find best price bid trie ", "orderbook", te.orderBookHash.Hex())
return EmptyHash return EmptyHash
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -190,27 +190,27 @@ func (c *tradingExchanges) getBestBidsTrie(db Database) common.Hash {
return EmptyHash return EmptyHash
} }
price := common.BytesToHash(encKey) price := common.BytesToHash(encKey)
if _, exit := c.stateBidObjects[price]; !exit { if _, exit := te.stateBidObjects[price]; !exit {
var data orderList var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best bid trie", "err", err) log.Error("Failed to decode state get best bid trie", "err", err)
return EmptyHash return EmptyHash
} }
// Insert into the live set. // Insert into the live set.
obj := newStateOrderList(c.db, Bid, c.orderBookHash, price, data, c.MarkStateBidObjectDirty) obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateBidObjectDirty)
c.stateBidObjects[price] = obj te.stateBidObjects[price] = obj
} }
return common.BytesToHash(encKey) return common.BytesToHash(encKey)
} }
// updateAskTrie writes cached storage modifications into the object's storage trie. // updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *tradingExchanges) updateAsksTrie(db Database) Trie { func (te *tradingExchanges) updateAsksTrie(db Database) Trie {
tr := self.getAsksTrie(db) tr := te.getAsksTrie(db)
for price, orderList := range self.stateAskObjects { for price, orderList := range te.stateAskObjects {
if _, isDirty := self.stateAskObjectsDirty[price]; isDirty { if _, isDirty := te.stateAskObjectsDirty[price]; isDirty {
delete(self.stateAskObjectsDirty, price) delete(te.stateAskObjectsDirty, price)
if orderList.empty() { if orderList.empty() {
self.setError(tr.TryDelete(price[:])) te.setError(tr.TryDelete(price[:]))
continue continue
} }
err := orderList.updateRoot(db) err := orderList.updateRoot(db)
@ -219,7 +219,7 @@ func (self *tradingExchanges) updateAsksTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderList) v, _ := rlp.EncodeToBytes(orderList)
self.setError(tr.TryUpdate(price[:], v)) te.setError(tr.TryUpdate(price[:], v))
} }
} }
@ -228,23 +228,23 @@ func (self *tradingExchanges) updateAsksTrie(db Database) Trie {
// CommitAskTrie the storage trie of the object to dwb. // CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root. // This updates the trie root.
func (self *tradingExchanges) updateAsksRoot(db Database) error { func (te *tradingExchanges) updateAsksRoot(db Database) error {
self.updateAsksTrie(db) te.updateAsksTrie(db)
if self.dbErr != nil { if te.dbErr != nil {
return self.dbErr return te.dbErr
} }
self.data.AskRoot = self.asksTrie.Hash() te.data.AskRoot = te.asksTrie.Hash()
return nil return nil
} }
// CommitAskTrie the storage trie of the object to dwb. // CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root. // This updates the trie root.
func (self *tradingExchanges) CommitAsksTrie(db Database) error { func (te *tradingExchanges) CommitAsksTrie(db Database) error {
self.updateAsksTrie(db) te.updateAsksTrie(db)
if self.dbErr != nil { if te.dbErr != nil {
return self.dbErr return te.dbErr
} }
root, err := self.asksTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := te.asksTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList orderList var orderList orderList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -255,31 +255,31 @@ func (self *tradingExchanges) CommitAsksTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.AskRoot = root te.data.AskRoot = root
} }
return err return err
} }
func (c *tradingExchanges) getBidsTrie(db Database) Trie { func (te *tradingExchanges) getBidsTrie(db Database) Trie {
if c.bidsTrie == nil { if te.bidsTrie == nil {
var err error var err error
c.bidsTrie, err = db.OpenStorageTrie(c.orderBookHash, c.data.BidRoot) te.bidsTrie, err = db.OpenStorageTrie(te.orderBookHash, te.data.BidRoot)
if err != nil { if err != nil {
c.bidsTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash) te.bidsTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create bids trie: %v", err)) te.setError(fmt.Errorf("can't create bids trie: %v", err))
} }
} }
return c.bidsTrie return te.bidsTrie
} }
// updateAskTrie writes cached storage modifications into the object's storage trie. // updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *tradingExchanges) updateBidsTrie(db Database) Trie { func (te *tradingExchanges) updateBidsTrie(db Database) Trie {
tr := self.getBidsTrie(db) tr := te.getBidsTrie(db)
for price, orderList := range self.stateBidObjects { for price, orderList := range te.stateBidObjects {
if _, isDirty := self.stateBidObjectsDirty[price]; isDirty { if _, isDirty := te.stateBidObjectsDirty[price]; isDirty {
delete(self.stateBidObjectsDirty, price) delete(te.stateBidObjectsDirty, price)
if orderList.empty() { if orderList.empty() {
self.setError(tr.TryDelete(price[:])) te.setError(tr.TryDelete(price[:]))
continue continue
} }
err := orderList.updateRoot(db) err := orderList.updateRoot(db)
@ -288,25 +288,25 @@ func (self *tradingExchanges) updateBidsTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderList) v, _ := rlp.EncodeToBytes(orderList)
self.setError(tr.TryUpdate(price[:], v)) te.setError(tr.TryUpdate(price[:], v))
} }
} }
return tr return tr
} }
func (self *tradingExchanges) updateBidsRoot(db Database) { func (te *tradingExchanges) updateBidsRoot(db Database) {
self.updateBidsTrie(db) te.updateBidsTrie(db)
self.data.BidRoot = self.bidsTrie.Hash() te.data.BidRoot = te.bidsTrie.Hash()
} }
// CommitAskTrie the storage trie of the object to dwb. // CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root. // This updates the trie root.
func (self *tradingExchanges) CommitBidsTrie(db Database) error { func (te *tradingExchanges) CommitBidsTrie(db Database) error {
self.updateBidsTrie(db) te.updateBidsTrie(db)
if self.dbErr != nil { if te.dbErr != nil {
return self.dbErr return te.dbErr
} }
root, err := self.bidsTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := te.bidsTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList orderList var orderList orderList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -317,116 +317,116 @@ func (self *tradingExchanges) CommitBidsTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.BidRoot = root te.data.BidRoot = root
} }
return err return err
} }
func (self *tradingExchanges) deepCopy(db *TradingStateDB, onDirty func(hash common.Hash)) *tradingExchanges { func (te *tradingExchanges) deepCopy(db *TradingStateDB, onDirty func(hash common.Hash)) *tradingExchanges {
stateExchanges := newStateExchanges(db, self.orderBookHash, self.data, onDirty) stateExchanges := newStateExchanges(db, te.orderBookHash, te.data, onDirty)
if self.asksTrie != nil { if te.asksTrie != nil {
stateExchanges.asksTrie = db.db.CopyTrie(self.asksTrie) stateExchanges.asksTrie = db.db.CopyTrie(te.asksTrie)
} }
if self.bidsTrie != nil { if te.bidsTrie != nil {
stateExchanges.bidsTrie = db.db.CopyTrie(self.bidsTrie) stateExchanges.bidsTrie = db.db.CopyTrie(te.bidsTrie)
} }
if self.ordersTrie != nil { if te.ordersTrie != nil {
stateExchanges.ordersTrie = db.db.CopyTrie(self.ordersTrie) stateExchanges.ordersTrie = db.db.CopyTrie(te.ordersTrie)
} }
for price, bidObject := range self.stateBidObjects { for price, bidObject := range te.stateBidObjects {
stateExchanges.stateBidObjects[price] = bidObject.deepCopy(db, self.MarkStateBidObjectDirty) stateExchanges.stateBidObjects[price] = bidObject.deepCopy(db, te.MarkStateBidObjectDirty)
} }
for price := range self.stateBidObjectsDirty { for price := range te.stateBidObjectsDirty {
stateExchanges.stateBidObjectsDirty[price] = struct{}{} stateExchanges.stateBidObjectsDirty[price] = struct{}{}
} }
for price, askObject := range self.stateAskObjects { for price, askObject := range te.stateAskObjects {
stateExchanges.stateAskObjects[price] = askObject.deepCopy(db, self.MarkStateAskObjectDirty) stateExchanges.stateAskObjects[price] = askObject.deepCopy(db, te.MarkStateAskObjectDirty)
} }
for price := range self.stateAskObjectsDirty { for price := range te.stateAskObjectsDirty {
stateExchanges.stateAskObjectsDirty[price] = struct{}{} stateExchanges.stateAskObjectsDirty[price] = struct{}{}
} }
for orderId, orderItem := range self.stateOrderObjects { for orderId, orderItem := range te.stateOrderObjects {
stateExchanges.stateOrderObjects[orderId] = orderItem.deepCopy(self.MarkStateOrderObjectDirty) stateExchanges.stateOrderObjects[orderId] = orderItem.deepCopy(te.MarkStateOrderObjectDirty)
} }
for orderId := range self.stateOrderObjectsDirty { for orderId := range te.stateOrderObjectsDirty {
stateExchanges.stateOrderObjectsDirty[orderId] = struct{}{} stateExchanges.stateOrderObjectsDirty[orderId] = struct{}{}
} }
for price, liquidationPrice := range self.liquidationPriceStates { for price, liquidationPrice := range te.liquidationPriceStates {
stateExchanges.liquidationPriceStates[price] = liquidationPrice.deepCopy(db, self.MarkStateLiquidationPriceDirty) stateExchanges.liquidationPriceStates[price] = liquidationPrice.deepCopy(db, te.MarkStateLiquidationPriceDirty)
} }
for price := range self.liquidationPriceStatesDirty { for price := range te.liquidationPriceStatesDirty {
stateExchanges.liquidationPriceStatesDirty[price] = struct{}{} stateExchanges.liquidationPriceStatesDirty[price] = struct{}{}
} }
return stateExchanges return stateExchanges
} }
// Returns the address of the contract/orderId // Returns the address of the contract/orderId
func (c *tradingExchanges) Hash() common.Hash { func (te *tradingExchanges) Hash() common.Hash {
return c.orderBookHash return te.orderBookHash
} }
func (self *tradingExchanges) SetNonce(nonce uint64) { func (te *tradingExchanges) SetNonce(nonce uint64) {
self.setNonce(nonce) te.setNonce(nonce)
} }
func (self *tradingExchanges) setNonce(nonce uint64) { func (te *tradingExchanges) setNonce(nonce uint64) {
self.data.Nonce = nonce te.data.Nonce = nonce
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
func (self *tradingExchanges) Nonce() uint64 { func (te *tradingExchanges) Nonce() uint64 {
return self.data.Nonce return te.data.Nonce
} }
func (self *tradingExchanges) setLastPrice(price *big.Int) { func (te *tradingExchanges) setLastPrice(price *big.Int) {
self.data.LastPrice = price te.data.LastPrice = price
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
func (self *tradingExchanges) setMediumPriceBeforeEpoch(price *big.Int) { func (te *tradingExchanges) setMediumPriceBeforeEpoch(price *big.Int) {
self.data.MediumPriceBeforeEpoch = price te.data.MediumPriceBeforeEpoch = price
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
func (self *tradingExchanges) setMediumPrice(price *big.Int, quantity *big.Int) { func (te *tradingExchanges) setMediumPrice(price *big.Int, quantity *big.Int) {
self.data.MediumPrice = price te.data.MediumPrice = price
self.data.TotalQuantity = quantity te.data.TotalQuantity = quantity
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
// updateStateExchangeObject writes the given object to the trie. // updateStateExchangeObject writes the given object to the trie.
func (self *tradingExchanges) removeStateOrderListAskObject(db Database, stateOrderList *stateOrderList) { func (te *tradingExchanges) removeStateOrderListAskObject(db Database, stateOrderList *stateOrderList) {
self.setError(self.asksTrie.TryDelete(stateOrderList.price[:])) te.setError(te.asksTrie.TryDelete(stateOrderList.price[:]))
} }
// updateStateExchangeObject writes the given object to the trie. // updateStateExchangeObject writes the given object to the trie.
func (self *tradingExchanges) removeStateOrderListBidObject(db Database, stateOrderList *stateOrderList) { func (te *tradingExchanges) removeStateOrderListBidObject(db Database, stateOrderList *stateOrderList) {
self.setError(self.bidsTrie.TryDelete(stateOrderList.price[:])) te.setError(te.bidsTrie.TryDelete(stateOrderList.price[:]))
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *tradingExchanges) getStateOrderListAskObject(db Database, price common.Hash) (stateOrderList *stateOrderList) { func (te *tradingExchanges) getStateOrderListAskObject(db Database, price common.Hash) (stateOrderList *stateOrderList) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.stateAskObjects[price]; obj != nil { if obj := te.stateAskObjects[price]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getAsksTrie(db).TryGet(price[:]) enc, err := te.getAsksTrie(db).TryGet(price[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) te.setError(err)
return nil return nil
} }
var data orderList var data orderList
@ -435,50 +435,50 @@ func (self *tradingExchanges) getStateOrderListAskObject(db Database, price comm
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateOrderList(self.db, Bid, self.orderBookHash, price, data, self.MarkStateAskObjectDirty) obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateAskObjectDirty)
self.stateAskObjects[price] = obj te.stateAskObjects[price] = obj
return obj return obj
} }
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly // MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones. // state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateAskObjectDirty(price common.Hash) { func (te *tradingExchanges) MarkStateAskObjectDirty(price common.Hash) {
self.stateAskObjectsDirty[price] = struct{}{} te.stateAskObjectsDirty[price] = struct{}{}
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
// createStateOrderListObject creates a new state object. If there is an existing orderId with // createStateOrderListObject creates a new state object. If there is an existing orderId with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *tradingExchanges) createStateOrderListAskObject(db Database, price common.Hash) (newobj *stateOrderList) { func (te *tradingExchanges) createStateOrderListAskObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(self.db, Ask, self.orderBookHash, price, orderList{Volume: Zero}, self.MarkStateAskObjectDirty) newobj = newStateOrderList(te.db, Ask, te.orderBookHash, price, orderList{Volume: Zero}, te.MarkStateAskObjectDirty)
self.stateAskObjects[price] = newobj te.stateAskObjects[price] = newobj
self.stateAskObjectsDirty[price] = struct{}{} te.stateAskObjectsDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err)) panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
} }
self.setError(self.asksTrie.TryUpdate(price[:], data)) te.setError(te.asksTrie.TryUpdate(price[:], data))
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
return newobj return newobj
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *tradingExchanges) getStateBidOrderListObject(db Database, price common.Hash) (stateOrderList *stateOrderList) { func (te *tradingExchanges) getStateBidOrderListObject(db Database, price common.Hash) (stateOrderList *stateOrderList) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.stateBidObjects[price]; obj != nil { if obj := te.stateBidObjects[price]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getBidsTrie(db).TryGet(price[:]) enc, err := te.getBidsTrie(db).TryGet(price[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) te.setError(err)
return nil return nil
} }
var data orderList var data orderList
@ -487,50 +487,50 @@ func (self *tradingExchanges) getStateBidOrderListObject(db Database, price comm
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateOrderList(self.db, Bid, self.orderBookHash, price, data, self.MarkStateBidObjectDirty) obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateBidObjectDirty)
self.stateBidObjects[price] = obj te.stateBidObjects[price] = obj
return obj return obj
} }
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly // MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones. // state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateBidObjectDirty(price common.Hash) { func (te *tradingExchanges) MarkStateBidObjectDirty(price common.Hash) {
self.stateBidObjectsDirty[price] = struct{}{} te.stateBidObjectsDirty[price] = struct{}{}
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
// createStateOrderListObject creates a new state object. If there is an existing orderId with // createStateOrderListObject creates a new state object. If there is an existing orderId with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *tradingExchanges) createStateBidOrderListObject(db Database, price common.Hash) (newobj *stateOrderList) { func (te *tradingExchanges) createStateBidOrderListObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(self.db, Bid, self.orderBookHash, price, orderList{Volume: Zero}, self.MarkStateBidObjectDirty) newobj = newStateOrderList(te.db, Bid, te.orderBookHash, price, orderList{Volume: Zero}, te.MarkStateBidObjectDirty)
self.stateBidObjects[price] = newobj te.stateBidObjects[price] = newobj
self.stateBidObjectsDirty[price] = struct{}{} te.stateBidObjectsDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err)) panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
} }
self.setError(self.bidsTrie.TryUpdate(price[:], data)) te.setError(te.bidsTrie.TryUpdate(price[:], data))
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
return newobj return newobj
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *tradingExchanges) getStateOrderObject(db Database, orderId common.Hash) (stateOrderItem *stateOrderItem) { func (te *tradingExchanges) getStateOrderObject(db Database, orderId common.Hash) (stateOrderItem *stateOrderItem) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.stateOrderObjects[orderId]; obj != nil { if obj := te.stateOrderObjects[orderId]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getOrdersTrie(db).TryGet(orderId[:]) enc, err := te.getOrdersTrie(db).TryGet(orderId[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) te.setError(err)
return nil return nil
} }
var data OrderItem var data OrderItem
@ -539,48 +539,48 @@ func (self *tradingExchanges) getStateOrderObject(db Database, orderId common.Ha
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateOrderItem(self.orderBookHash, orderId, data, self.MarkStateOrderObjectDirty) obj := newStateOrderItem(te.orderBookHash, orderId, data, te.MarkStateOrderObjectDirty)
self.stateOrderObjects[orderId] = obj te.stateOrderObjects[orderId] = obj
return obj return obj
} }
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly // MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones. // state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateOrderObjectDirty(orderId common.Hash) { func (te *tradingExchanges) MarkStateOrderObjectDirty(orderId common.Hash) {
self.stateOrderObjectsDirty[orderId] = struct{}{} te.stateOrderObjectsDirty[orderId] = struct{}{}
if self.onDirty != nil { if te.onDirty != nil {
self.onDirty(self.Hash()) te.onDirty(te.Hash())
self.onDirty = nil te.onDirty = nil
} }
} }
// createStateOrderListObject creates a new state object. If there is an existing orderId with // createStateOrderListObject creates a new state object. If there is an existing orderId with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *tradingExchanges) createStateOrderObject(db Database, orderId common.Hash, order OrderItem) (newobj *stateOrderItem) { func (t *tradingExchanges) createStateOrderObject(db Database, orderId common.Hash, order OrderItem) (newobj *stateOrderItem) {
newobj = newStateOrderItem(self.orderBookHash, orderId, order, self.MarkStateOrderObjectDirty) newobj = newStateOrderItem(t.orderBookHash, orderId, order, t.MarkStateOrderObjectDirty)
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.OrderID)) orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.OrderID))
self.stateOrderObjects[orderIdHash] = newobj t.stateOrderObjects[orderIdHash] = newobj
self.stateOrderObjectsDirty[orderIdHash] = struct{}{} t.stateOrderObjectsDirty[orderIdHash] = struct{}{}
if self.onDirty != nil { if t.onDirty != nil {
self.onDirty(self.orderBookHash) t.onDirty(t.orderBookHash)
self.onDirty = nil t.onDirty = nil
} }
return newobj return newobj
} }
// updateAskTrie writes cached storage modifications into the object's storage trie. // updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *tradingExchanges) updateOrdersTrie(db Database) Trie { func (t *tradingExchanges) updateOrdersTrie(db Database) Trie {
tr := self.getOrdersTrie(db) tr := t.getOrdersTrie(db)
for orderId, orderItem := range self.stateOrderObjects { for orderId, orderItem := range t.stateOrderObjects {
if _, isDirty := self.stateOrderObjectsDirty[orderId]; isDirty { if _, isDirty := t.stateOrderObjectsDirty[orderId]; isDirty {
delete(self.stateOrderObjectsDirty, orderId) delete(t.stateOrderObjectsDirty, orderId)
if orderItem.empty() { if orderItem.empty() {
self.setError(tr.TryDelete(orderId[:])) t.setError(tr.TryDelete(orderId[:]))
continue continue
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderItem) v, _ := rlp.EncodeToBytes(orderItem)
self.setError(tr.TryUpdate(orderId[:], v)) t.setError(tr.TryUpdate(orderId[:], v))
} }
} }
return tr return tr
@ -588,71 +588,71 @@ func (self *tradingExchanges) updateOrdersTrie(db Database) Trie {
// CommitAskTrie the storage trie of the object to dwb. // CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root. // This updates the trie root.
func (self *tradingExchanges) updateOrdersRoot(db Database) { func (t *tradingExchanges) updateOrdersRoot(db Database) {
self.updateOrdersTrie(db) t.updateOrdersTrie(db)
self.data.OrderRoot = self.ordersTrie.Hash() t.data.OrderRoot = t.ordersTrie.Hash()
} }
// CommitAskTrie the storage trie of the object to dwb. // CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root. // This updates the trie root.
func (self *tradingExchanges) CommitOrdersTrie(db Database) error { func (t *tradingExchanges) CommitOrdersTrie(db Database) error {
self.updateOrdersTrie(db) t.updateOrdersTrie(db)
if self.dbErr != nil { if t.dbErr != nil {
return self.dbErr return t.dbErr
} }
root, err := self.ordersTrie.Commit(nil) root, err := t.ordersTrie.Commit(nil)
if err == nil { if err == nil {
self.data.OrderRoot = root t.data.OrderRoot = root
} }
return err return err
} }
func (self *tradingExchanges) MarkStateLiquidationPriceDirty(price common.Hash) { func (t *tradingExchanges) MarkStateLiquidationPriceDirty(price common.Hash) {
self.liquidationPriceStatesDirty[price] = struct{}{} t.liquidationPriceStatesDirty[price] = struct{}{}
if self.onDirty != nil { if t.onDirty != nil {
self.onDirty(self.Hash()) t.onDirty(t.Hash())
self.onDirty = nil t.onDirty = nil
} }
} }
func (self *tradingExchanges) createStateLiquidationPrice(db Database, liquidationPrice common.Hash) (newobj *liquidationPriceState) { func (t *tradingExchanges) createStateLiquidationPrice(db Database, liquidationPrice common.Hash) (newobj *liquidationPriceState) {
newobj = newLiquidationPriceState(self.db, self.orderBookHash, liquidationPrice, orderList{Volume: Zero}, self.MarkStateLiquidationPriceDirty) newobj = newLiquidationPriceState(t.db, t.orderBookHash, liquidationPrice, orderList{Volume: Zero}, t.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[liquidationPrice] = newobj t.liquidationPriceStates[liquidationPrice] = newobj
self.liquidationPriceStatesDirty[liquidationPrice] = struct{}{} t.liquidationPriceStatesDirty[liquidationPrice] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode liquidation price object at %x: %v", liquidationPrice[:], err)) panic(fmt.Errorf("can't encode liquidation price object at %x: %v", liquidationPrice[:], err))
} }
self.setError(self.getLiquidationPriceTrie(db).TryUpdate(liquidationPrice[:], data)) t.setError(t.getLiquidationPriceTrie(db).TryUpdate(liquidationPrice[:], data))
if self.onDirty != nil { if t.onDirty != nil {
self.onDirty(self.Hash()) t.onDirty(t.Hash())
self.onDirty = nil t.onDirty = nil
} }
return newobj return newobj
} }
func (self *tradingExchanges) getLiquidationPriceTrie(db Database) Trie { func (t *tradingExchanges) getLiquidationPriceTrie(db Database) Trie {
if self.liquidationPriceTrie == nil { if t.liquidationPriceTrie == nil {
var err error var err error
self.liquidationPriceTrie, err = db.OpenStorageTrie(self.orderBookHash, self.data.LiquidationPriceRoot) t.liquidationPriceTrie, err = db.OpenStorageTrie(t.orderBookHash, t.data.LiquidationPriceRoot)
if err != nil { if err != nil {
self.liquidationPriceTrie, _ = db.OpenStorageTrie(self.orderBookHash, EmptyHash) t.liquidationPriceTrie, _ = db.OpenStorageTrie(t.orderBookHash, EmptyHash)
self.setError(fmt.Errorf("can't create liquidation liquidationPrice trie: %v", err)) t.setError(fmt.Errorf("can't create liquidation liquidationPrice trie: %v", err))
} }
} }
return self.liquidationPriceTrie return t.liquidationPriceTrie
} }
func (self *tradingExchanges) getStateLiquidationPrice(db Database, price common.Hash) (stateObject *liquidationPriceState) { func (t *tradingExchanges) getStateLiquidationPrice(db Database, price common.Hash) (stateObject *liquidationPriceState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.liquidationPriceStates[price]; obj != nil { if obj := t.liquidationPriceStates[price]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getLiquidationPriceTrie(db).TryGet(price[:]) enc, err := t.getLiquidationPriceTrie(db).TryGet(price[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) t.setError(err)
return nil return nil
} }
var data orderList var data orderList
@ -661,16 +661,16 @@ func (self *tradingExchanges) getStateLiquidationPrice(db Database, price common
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty) obj := newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj t.liquidationPriceStates[price] = obj
return obj return obj
} }
func (self *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) { func (t *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := self.getLiquidationPriceTrie(db) trie := t.getLiquidationPriceTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue() encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best liquidationPrice ask trie ", "orderbook", self.orderBookHash.Hex()) log.Error("Failed find best liquidationPrice ask trie ", "orderbook", t.orderBookHash.Hex())
return EmptyHash, nil return EmptyHash, nil
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -678,25 +678,25 @@ func (self *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Has
return EmptyHash, nil return EmptyHash, nil
} }
price := common.BytesToHash(encKey) price := common.BytesToHash(encKey)
obj := self.liquidationPriceStates[price] obj := t.liquidationPriceStates[price]
if obj == nil { if obj == nil {
var data orderList var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err) log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash, nil return EmptyHash, nil
} }
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty) obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj t.liquidationPriceStates[price] = obj
} }
return price, obj return price, obj
} }
func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit common.Hash) map[common.Hash]*liquidationPriceState { func (t *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit common.Hash) map[common.Hash]*liquidationPriceState {
trie := self.getLiquidationPriceTrie(db) trie := t.getLiquidationPriceTrie(db)
encKeys, encValues, err := trie.TryGetAllLeftKeyAndValue(limit.Bytes()) encKeys, encValues, err := trie.TryGetAllLeftKeyAndValue(limit.Bytes())
result := map[common.Hash]*liquidationPriceState{} result := map[common.Hash]*liquidationPriceState{}
if err != nil || len(encKeys) != len(encValues) { if err != nil || len(encKeys) != len(encValues) {
log.Error("Failed get lower liquidation price trie ", "orderbook", self.orderBookHash.Hex(), "encKeys", len(encKeys), "encValues", len(encValues)) log.Error("Failed get lower liquidation price trie ", "orderbook", t.orderBookHash.Hex(), "encKeys", len(encKeys), "encValues", len(encValues))
return result return result
} }
if len(encKeys) == 0 || len(encValues) == 0 { if len(encKeys) == 0 || len(encValues) == 0 {
@ -705,15 +705,15 @@ func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit com
} }
for i := range encKeys { for i := range encKeys {
price := common.BytesToHash(encKeys[i]) price := common.BytesToHash(encKeys[i])
obj := self.liquidationPriceStates[price] obj := t.liquidationPriceStates[price]
if obj == nil { if obj == nil {
var data orderList var data orderList
if err := rlp.DecodeBytes(encValues[i], &data); err != nil { if err := rlp.DecodeBytes(encValues[i], &data); err != nil {
log.Error("Failed to decode state get all lower liquidation price trie", "price", price, "encValues", encValues[i], "err", err) log.Error("Failed to decode state get all lower liquidation price trie", "price", price, "encValues", encValues[i], "err", err)
return result return result
} }
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty) obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj t.liquidationPriceStates[price] = obj
} }
if obj.empty() { if obj.empty() {
continue continue
@ -723,11 +723,11 @@ func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit com
return result return result
} }
func (self *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) { func (t *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := self.getLiquidationPriceTrie(db) trie := t.getLiquidationPriceTrie(db)
encKey, encValue, err := trie.TryGetBestRightKeyAndValue() encKey, encValue, err := trie.TryGetBestRightKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best liquidationPrice ask trie ", "orderbook", self.orderBookHash.Hex()) log.Error("Failed find best liquidationPrice ask trie ", "orderbook", t.orderBookHash.Hex())
return EmptyHash, nil return EmptyHash, nil
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -735,28 +735,29 @@ func (self *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Ha
return EmptyHash, nil return EmptyHash, nil
} }
price := common.BytesToHash(encKey) price := common.BytesToHash(encKey)
obj := self.liquidationPriceStates[price] obj := t.liquidationPriceStates[price]
if obj == nil { if obj == nil {
var data orderList var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err) log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash, nil return EmptyHash, nil
} }
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty) obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj t.liquidationPriceStates[price] = obj
} }
if obj.empty() { if obj.empty() {
return EmptyHash, nil return EmptyHash, nil
} }
return price, obj return price, obj
} }
func (self *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
tr := self.getLiquidationPriceTrie(db) func (t *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
for price, stateObject := range self.liquidationPriceStates { tr := t.getLiquidationPriceTrie(db)
if _, isDirty := self.liquidationPriceStatesDirty[price]; isDirty { for price, stateObject := range t.liquidationPriceStates {
delete(self.liquidationPriceStatesDirty, price) if _, isDirty := t.liquidationPriceStatesDirty[price]; isDirty {
delete(t.liquidationPriceStatesDirty, price)
if stateObject.empty() { if stateObject.empty() {
self.setError(tr.TryDelete(price[:])) t.setError(tr.TryDelete(price[:]))
continue continue
} }
err := stateObject.updateRoot(db) err := stateObject.updateRoot(db)
@ -765,23 +766,23 @@ func (self *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(stateObject) v, _ := rlp.EncodeToBytes(stateObject)
self.setError(tr.TryUpdate(price[:], v)) t.setError(tr.TryUpdate(price[:], v))
} }
} }
return tr return tr
} }
func (self *tradingExchanges) updateLiquidationPriceRoot(db Database) { func (t *tradingExchanges) updateLiquidationPriceRoot(db Database) {
self.updateLiquidationPriceTrie(db) t.updateLiquidationPriceTrie(db)
self.data.LiquidationPriceRoot = self.liquidationPriceTrie.Hash() t.data.LiquidationPriceRoot = t.liquidationPriceTrie.Hash()
} }
func (self *tradingExchanges) CommitLiquidationPriceTrie(db Database) error { func (t *tradingExchanges) CommitLiquidationPriceTrie(db Database) error {
self.updateLiquidationPriceTrie(db) t.updateLiquidationPriceTrie(db)
if self.dbErr != nil { if t.dbErr != nil {
return self.dbErr return t.dbErr
} }
root, err := self.liquidationPriceTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := t.liquidationPriceTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList orderList var orderList orderList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -792,23 +793,23 @@ func (self *tradingExchanges) CommitLiquidationPriceTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.LiquidationPriceRoot = root t.data.LiquidationPriceRoot = root
} }
return err return err
} }
func (c *tradingExchanges) addLendingCount(amount *big.Int) { func (t *tradingExchanges) addLendingCount(amount *big.Int) {
c.setLendingCount(new(big.Int).Add(c.data.LendingCount, amount)) t.setLendingCount(new(big.Int).Add(t.data.LendingCount, amount))
} }
func (c *tradingExchanges) subLendingCount(amount *big.Int) { func (t *tradingExchanges) subLendingCount(amount *big.Int) {
c.setLendingCount(new(big.Int).Sub(c.data.LendingCount, amount)) t.setLendingCount(new(big.Int).Sub(t.data.LendingCount, amount))
} }
func (self *tradingExchanges) setLendingCount(volume *big.Int) { func (t *tradingExchanges) setLendingCount(volume *big.Int) {
self.data.LendingCount = volume t.data.LendingCount = volume
if self.onDirty != nil { if t.onDirty != nil {
self.onDirty(self.orderBookHash) t.onDirty(t.orderBookHash)
self.onDirty = nil t.onDirty = nil
} }
} }

View file

@ -78,55 +78,55 @@ func New(root common.Hash, db Database) (*TradingStateDB, error) {
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *TradingStateDB) setError(err error) { func (t *TradingStateDB) setError(err error) {
if self.dbErr == nil { if t.dbErr == nil {
self.dbErr = err t.dbErr = err
} }
} }
func (self *TradingStateDB) Error() error { func (t *TradingStateDB) Error() error {
return self.dbErr return t.dbErr
} }
// Exist reports whether the given orderId address exists in the state. // Exist reports whether the given orderId address exists in the state.
// Notably this also returns true for suicided exchanges. // Notably this also returns true for suicided exchanges.
func (self *TradingStateDB) Exist(addr common.Hash) bool { func (t *TradingStateDB) Exist(addr common.Hash) bool {
return self.getStateExchangeObject(addr) != nil return t.getStateExchangeObject(addr) != nil
} }
// Empty returns whether the state object is either non-existent // Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0) // or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *TradingStateDB) Empty(addr common.Hash) bool { func (t *TradingStateDB) Empty(addr common.Hash) bool {
so := self.getStateExchangeObject(addr) so := t.getStateExchangeObject(addr)
return so == nil || so.empty() return so == nil || so.empty()
} }
func (self *TradingStateDB) GetNonce(addr common.Hash) uint64 { func (t *TradingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := self.getStateExchangeObject(addr) stateObject := t.getStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Nonce() return stateObject.Nonce()
} }
return 0 return 0
} }
func (self *TradingStateDB) GetLastPrice(addr common.Hash) *big.Int { func (t *TradingStateDB) GetLastPrice(addr common.Hash) *big.Int {
stateObject := self.getStateExchangeObject(addr) stateObject := t.getStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.data.LastPrice return stateObject.data.LastPrice
} }
return nil return nil
} }
func (self *TradingStateDB) GetMediumPriceBeforeEpoch(addr common.Hash) *big.Int { func (t *TradingStateDB) GetMediumPriceBeforeEpoch(addr common.Hash) *big.Int {
stateObject := self.getStateExchangeObject(addr) stateObject := t.getStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.data.MediumPriceBeforeEpoch return stateObject.data.MediumPriceBeforeEpoch
} }
return Zero return Zero
} }
func (self *TradingStateDB) GetMediumPriceAndTotalAmount(addr common.Hash) (*big.Int, *big.Int) { func (t *TradingStateDB) GetMediumPriceAndTotalAmount(addr common.Hash) (*big.Int, *big.Int) {
stateObject := self.getStateExchangeObject(addr) stateObject := t.getStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.data.MediumPrice, stateObject.data.TotalQuantity return stateObject.data.MediumPrice, stateObject.data.TotalQuantity
} }
@ -134,25 +134,25 @@ func (self *TradingStateDB) GetMediumPriceAndTotalAmount(addr common.Hash) (*big
} }
// Database retrieves the low level database supporting the lower level trie ops. // Database retrieves the low level database supporting the lower level trie ops.
func (self *TradingStateDB) Database() Database { func (t *TradingStateDB) Database() Database {
return self.db return t.db
} }
func (self *TradingStateDB) SetNonce(addr common.Hash, nonce uint64) { func (t *TradingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := self.GetOrNewStateExchangeObject(addr) stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, nonceChange{ t.journal = append(t.journal, nonceChange{
hash: addr, hash: addr,
prev: self.GetNonce(addr), prev: t.GetNonce(addr),
}) })
stateObject.SetNonce(nonce) stateObject.SetNonce(nonce)
} }
} }
func (self *TradingStateDB) SetLastPrice(addr common.Hash, price *big.Int) { func (t *TradingStateDB) SetLastPrice(addr common.Hash, price *big.Int) {
stateObject := self.GetOrNewStateExchangeObject(addr) stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, lastPriceChange{ t.journal = append(t.journal, lastPriceChange{
hash: addr, hash: addr,
prev: stateObject.data.LastPrice, prev: stateObject.data.LastPrice,
}) })
@ -160,10 +160,10 @@ func (self *TradingStateDB) SetLastPrice(addr common.Hash, price *big.Int) {
} }
} }
func (self *TradingStateDB) SetMediumPrice(addr common.Hash, price *big.Int, quantity *big.Int) { func (t *TradingStateDB) SetMediumPrice(addr common.Hash, price *big.Int, quantity *big.Int) {
stateObject := self.GetOrNewStateExchangeObject(addr) stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, mediumPriceChange{ t.journal = append(t.journal, mediumPriceChange{
hash: addr, hash: addr,
prevPrice: stateObject.data.MediumPrice, prevPrice: stateObject.data.MediumPrice,
prevQuantity: stateObject.data.TotalQuantity, prevQuantity: stateObject.data.TotalQuantity,
@ -172,10 +172,10 @@ func (self *TradingStateDB) SetMediumPrice(addr common.Hash, price *big.Int, qua
} }
} }
func (self *TradingStateDB) SetMediumPriceBeforeEpoch(addr common.Hash, price *big.Int) { func (t *TradingStateDB) SetMediumPriceBeforeEpoch(addr common.Hash, price *big.Int) {
stateObject := self.GetOrNewStateExchangeObject(addr) stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, mediumPriceBeforeEpochChange{ t.journal = append(t.journal, mediumPriceBeforeEpochChange{
hash: addr, hash: addr,
prevPrice: stateObject.data.MediumPriceBeforeEpoch, prevPrice: stateObject.data.MediumPriceBeforeEpoch,
}) })
@ -183,78 +183,79 @@ func (self *TradingStateDB) SetMediumPriceBeforeEpoch(addr common.Hash, price *b
} }
} }
func (self *TradingStateDB) InsertOrderItem(orderBook common.Hash, orderId common.Hash, order OrderItem) { func (t *TradingStateDB) InsertOrderItem(orderBook common.Hash, orderId common.Hash, order OrderItem) {
priceHash := common.BigToHash(order.Price) priceHash := common.BigToHash(order.Price)
stateExchange := self.getStateExchangeObject(orderBook) stateExchange := t.getStateExchangeObject(orderBook)
if stateExchange == nil { if stateExchange == nil {
stateExchange = self.createExchangeObject(orderBook) stateExchange = t.createExchangeObject(orderBook)
} }
var stateOrderList *stateOrderList var stateOrderList *stateOrderList
switch order.Side { switch order.Side {
case Ask: case Ask:
stateOrderList = stateExchange.getStateOrderListAskObject(self.db, priceHash) stateOrderList = stateExchange.getStateOrderListAskObject(t.db, priceHash)
if stateOrderList == nil { if stateOrderList == nil {
stateOrderList = stateExchange.createStateOrderListAskObject(self.db, priceHash) stateOrderList = stateExchange.createStateOrderListAskObject(t.db, priceHash)
} }
case Bid: case Bid:
stateOrderList = stateExchange.getStateBidOrderListObject(self.db, priceHash) stateOrderList = stateExchange.getStateBidOrderListObject(t.db, priceHash)
if stateOrderList == nil { if stateOrderList == nil {
stateOrderList = stateExchange.createStateBidOrderListObject(self.db, priceHash) stateOrderList = stateExchange.createStateBidOrderListObject(t.db, priceHash)
} }
default: default:
return return
} }
self.journal = append(self.journal, insertOrder{ t.journal = append(t.journal, insertOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderId, orderId: orderId,
order: &order, order: &order,
}) })
stateExchange.createStateOrderObject(self.db, orderId, order) stateExchange.createStateOrderObject(t.db, orderId, order)
stateOrderList.insertOrderItem(self.db, orderId, common.BigToHash(order.Quantity)) stateOrderList.insertOrderItem(t.db, orderId, common.BigToHash(order.Quantity))
stateOrderList.AddVolume(order.Quantity) stateOrderList.AddVolume(order.Quantity)
} }
func (self *TradingStateDB) GetOrder(orderBook common.Hash, orderId common.Hash) OrderItem { func (t *TradingStateDB) GetOrder(orderBook common.Hash, orderId common.Hash) OrderItem {
stateObject := self.GetOrNewStateExchangeObject(orderBook) stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return EmptyOrder return EmptyOrder
} }
stateOrderItem := stateObject.getStateOrderObject(self.db, orderId) stateOrderItem := stateObject.getStateOrderObject(t.db, orderId)
if stateOrderItem == nil { if stateOrderItem == nil {
return EmptyOrder return EmptyOrder
} }
return stateOrderItem.data return stateOrderItem.data
} }
func (self *TradingStateDB) SubAmountOrderItem(orderBook common.Hash, orderId common.Hash, price *big.Int, amount *big.Int, side string) error {
func (t *TradingStateDB) SubAmountOrderItem(orderBook common.Hash, orderId common.Hash, price *big.Int, amount *big.Int, side string) error {
priceHash := common.BigToHash(price) priceHash := common.BigToHash(price)
stateObject := self.GetOrNewStateExchangeObject(orderBook) stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return fmt.Errorf("Order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found orderBook: %s", orderBook.Hex())
} }
var stateOrderList *stateOrderList var stateOrderList *stateOrderList
switch side { switch side {
case Ask: case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, priceHash) stateOrderList = stateObject.getStateOrderListAskObject(t.db, priceHash)
case Bid: case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, priceHash) stateOrderList = stateObject.getStateBidOrderListObject(t.db, priceHash)
default: default:
return fmt.Errorf("Order type not found : %s ", side) return fmt.Errorf("not found order type: %s", side)
} }
if stateOrderList == nil || stateOrderList.empty() { if stateOrderList == nil || stateOrderList.empty() {
return fmt.Errorf("Order list empty order book : %s , order id : %s , price : %s ", orderBook, orderId.Hex(), priceHash.Hex()) return fmt.Errorf("empty Orderlist: order book: %s , order id : %s , price : %s", orderBook, orderId.Hex(), priceHash.Hex())
} }
stateOrderItem := stateObject.getStateOrderObject(self.db, orderId) stateOrderItem := stateObject.getStateOrderObject(t.db, orderId)
if stateOrderItem == nil || stateOrderItem.empty() { if stateOrderItem == nil || stateOrderItem.empty() {
return fmt.Errorf("Order item empty order book : %s , order id : %s , price : %s ", orderBook, orderId.Hex(), priceHash.Hex()) return fmt.Errorf("empty OrderItem: order book: %s , order id : %s , price : %s", orderBook, orderId.Hex(), priceHash.Hex())
} }
currentAmount := new(big.Int).SetBytes(stateOrderList.GetOrderAmount(self.db, orderId).Bytes()[:]) currentAmount := new(big.Int).SetBytes(stateOrderList.GetOrderAmount(t.db, orderId).Bytes()[:])
if currentAmount.Cmp(amount) < 0 { if currentAmount.Cmp(amount) < 0 {
return fmt.Errorf("Order amount not enough : %s , have : %d , want : %d ", orderId.Hex(), currentAmount, amount) return fmt.Errorf("not enough order amount: %s , have : %d , want : %d ", orderId.Hex(), currentAmount, amount)
} }
self.journal = append(self.journal, subAmountOrder{ t.journal = append(t.journal, subAmountOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderId, orderId: orderId,
order: self.GetOrder(orderBook, orderId), order: t.GetOrder(orderBook, orderId),
amount: amount, amount: amount,
}) })
newAmount := new(big.Int).Sub(currentAmount, amount) newAmount := new(big.Int).Sub(currentAmount, amount)
@ -262,86 +263,86 @@ func (self *TradingStateDB) SubAmountOrderItem(orderBook common.Hash, orderId co
stateOrderList.subVolume(amount) stateOrderList.subVolume(amount)
stateOrderItem.setVolume(newAmount) stateOrderItem.setVolume(newAmount)
if newAmount.Sign() == 0 { if newAmount.Sign() == 0 {
stateOrderList.removeOrderItem(self.db, orderId) stateOrderList.removeOrderItem(t.db, orderId)
} else { } else {
stateOrderList.setOrderItem(orderId, common.BigToHash(newAmount)) stateOrderList.setOrderItem(orderId, common.BigToHash(newAmount))
} }
if stateOrderList.empty() { if stateOrderList.empty() {
switch side { switch side {
case Ask: case Ask:
stateObject.removeStateOrderListAskObject(self.db, stateOrderList) stateObject.removeStateOrderListAskObject(t.db, stateOrderList)
case Bid: case Bid:
stateObject.removeStateOrderListBidObject(self.db, stateOrderList) stateObject.removeStateOrderListBidObject(t.db, stateOrderList)
default: default:
} }
} }
return nil return nil
} }
func (self *TradingStateDB) CancelOrder(orderBook common.Hash, order *OrderItem) error { func (t *TradingStateDB) CancelOrder(orderBook common.Hash, order *OrderItem) error {
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.OrderID)) orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.OrderID))
stateObject := self.GetOrNewStateExchangeObject(orderBook) stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return fmt.Errorf("Order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found orderBook: %s", orderBook.Hex())
} }
stateOrderItem := stateObject.getStateOrderObject(self.db, orderIdHash) stateOrderItem := stateObject.getStateOrderObject(t.db, orderIdHash)
if stateOrderItem == nil || stateOrderItem.empty() { if stateOrderItem == nil || stateOrderItem.empty() {
return fmt.Errorf("Order item empty order book : %s , order id : %s ", orderBook, orderIdHash.Hex()) return fmt.Errorf("empty OrderItem: order book: %s , order id : %s", orderBook, orderIdHash.Hex())
} }
priceHash := common.BigToHash(stateOrderItem.data.Price) priceHash := common.BigToHash(stateOrderItem.data.Price)
var stateOrderList *stateOrderList var stateOrderList *stateOrderList
switch stateOrderItem.data.Side { switch stateOrderItem.data.Side {
case Ask: case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, priceHash) stateOrderList = stateObject.getStateOrderListAskObject(t.db, priceHash)
case Bid: case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, priceHash) stateOrderList = stateObject.getStateBidOrderListObject(t.db, priceHash)
default: default:
return fmt.Errorf("Order side not found : %s ", order.Side) return fmt.Errorf("not found order.Side: %s", order.Side)
} }
if stateOrderList == nil || stateOrderList.empty() { if stateOrderList == nil || stateOrderList.empty() {
return fmt.Errorf("Order list empty order book : %s , order id : %s , price : %s ", orderBook, orderIdHash.Hex(), priceHash.Hex()) return fmt.Errorf("empty OrderList: order book: %s , order id : %s , price : %s", orderBook, orderIdHash.Hex(), priceHash.Hex())
} }
if stateOrderItem.data.UserAddress != order.UserAddress { if stateOrderItem.data.UserAddress != order.UserAddress {
return fmt.Errorf("Error Order User Address mismatch when cancel order book : %s , order id : %s , got : %s , expect : %s ", orderBook, orderIdHash.Hex(), stateOrderItem.data.UserAddress.Hex(), order.UserAddress.Hex()) return fmt.Errorf("error Order UserAddress mismatch when cancel: order book: %s , order id : %s , got : %s , expect : %s", orderBook, orderIdHash.Hex(), stateOrderItem.data.UserAddress.Hex(), order.UserAddress.Hex())
} }
if stateOrderItem.data.Hash != order.Hash { if stateOrderItem.data.Hash != order.Hash {
return fmt.Errorf("Invalid order hash : got : %s , expect : %s ", order.Hash.Hex(), stateOrderItem.data.Hash.Hex()) return fmt.Errorf("invalid order hash: got : %s , expect : %s", order.Hash.Hex(), stateOrderItem.data.Hash.Hex())
} }
if stateOrderItem.data.ExchangeAddress != order.ExchangeAddress { if stateOrderItem.data.ExchangeAddress != order.ExchangeAddress {
return fmt.Errorf("Exchange Address mismatch when cancel. order book : %s , order id : %s , got : %s , expect : %s ", orderBook, orderIdHash.Hex(), order.ExchangeAddress.Hex(), stateOrderItem.data.ExchangeAddress.Hex()) return fmt.Errorf("mismatch ExchangeAddress when cancel: order book : %s , order id : %s , got : %s , expect : %s", orderBook, orderIdHash.Hex(), order.ExchangeAddress.Hex(), stateOrderItem.data.ExchangeAddress.Hex())
} }
self.journal = append(self.journal, cancelOrder{ t.journal = append(t.journal, cancelOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderIdHash, orderId: orderIdHash,
order: stateOrderItem.data, order: stateOrderItem.data,
}) })
currentAmount := new(big.Int).SetBytes(stateOrderList.GetOrderAmount(self.db, orderIdHash).Bytes()[:]) currentAmount := new(big.Int).SetBytes(stateOrderList.GetOrderAmount(t.db, orderIdHash).Bytes()[:])
stateOrderItem.setVolume(big.NewInt(0)) stateOrderItem.setVolume(big.NewInt(0))
stateOrderList.subVolume(currentAmount) stateOrderList.subVolume(currentAmount)
stateOrderList.removeOrderItem(self.db, orderIdHash) stateOrderList.removeOrderItem(t.db, orderIdHash)
if stateOrderList.empty() { if stateOrderList.empty() {
switch stateOrderItem.data.Side { switch stateOrderItem.data.Side {
case Ask: case Ask:
stateObject.removeStateOrderListAskObject(self.db, stateOrderList) stateObject.removeStateOrderListAskObject(t.db, stateOrderList)
case Bid: case Bid:
stateObject.removeStateOrderListBidObject(self.db, stateOrderList) stateObject.removeStateOrderListBidObject(t.db, stateOrderList)
default: default:
} }
} }
return nil return nil
} }
func (self *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, orderType string) *big.Int { func (t *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, orderType string) *big.Int {
stateObject := self.GetOrNewStateExchangeObject(orderBook) stateObject := t.GetOrNewStateExchangeObject(orderBook)
var volume *big.Int = nil var volume *big.Int = nil
if stateObject != nil { if stateObject != nil {
var stateOrderList *stateOrderList var stateOrderList *stateOrderList
switch orderType { switch orderType {
case Ask: case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, common.BigToHash(price)) stateOrderList = stateObject.getStateOrderListAskObject(t.db, common.BigToHash(price))
case Bid: case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, common.BigToHash(price)) stateOrderList = stateObject.getStateBidOrderListObject(t.db, common.BigToHash(price))
default: default:
return Zero return Zero
} }
@ -352,14 +353,15 @@ func (self *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, ord
} }
return volume return volume
} }
func (self *TradingStateDB) GetBestAskPrice(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getStateExchangeObject(orderBook) func (t *TradingStateDB) GetBestAskPrice(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := t.getStateExchangeObject(orderBook)
if stateObject != nil { if stateObject != nil {
priceHash := stateObject.getBestPriceAsksTrie(self.db) priceHash := stateObject.getBestPriceAsksTrie(t.db)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
return Zero, Zero return Zero, Zero
} }
orderList := stateObject.getStateOrderListAskObject(self.db, priceHash) orderList := stateObject.getStateOrderListAskObject(t.db, priceHash)
if orderList == nil { if orderList == nil {
log.Error("order list ask not found", "price", priceHash.Hex()) log.Error("order list ask not found", "price", priceHash.Hex())
return Zero, Zero return Zero, Zero
@ -369,14 +371,14 @@ func (self *TradingStateDB) GetBestAskPrice(orderBook common.Hash) (*big.Int, *b
return Zero, Zero return Zero, Zero
} }
func (self *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *big.Int) { func (t *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getStateExchangeObject(orderBook) stateObject := t.getStateExchangeObject(orderBook)
if stateObject != nil { if stateObject != nil {
priceHash := stateObject.getBestBidsTrie(self.db) priceHash := stateObject.getBestBidsTrie(t.db)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
return Zero, Zero return Zero, Zero
} }
orderList := stateObject.getStateBidOrderListObject(self.db, priceHash) orderList := stateObject.getStateBidOrderListObject(t.db, priceHash)
if orderList == nil { if orderList == nil {
log.Error("order list bid not found", "price", priceHash.Hex()) log.Error("order list bid not found", "price", priceHash.Hex())
return Zero, Zero return Zero, Zero
@ -386,52 +388,52 @@ func (self *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *b
return Zero, Zero return Zero, Zero
} }
func (self *TradingStateDB) GetBestOrderIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) { func (t *TradingStateDB) GetBestOrderIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := self.GetOrNewStateExchangeObject(orderBook) stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject != nil { if stateObject != nil {
var stateOrderList *stateOrderList var stateOrderList *stateOrderList
switch side { switch side {
case Ask: case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, common.BigToHash(price)) stateOrderList = stateObject.getStateOrderListAskObject(t.db, common.BigToHash(price))
case Bid: case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, common.BigToHash(price)) stateOrderList = stateObject.getStateBidOrderListObject(t.db, common.BigToHash(price))
default: default:
return EmptyHash, Zero, fmt.Errorf("not found side :%s ", side) return EmptyHash, Zero, fmt.Errorf("not found side: %s", side)
} }
if stateOrderList != nil { if stateOrderList != nil {
key, _, err := stateOrderList.getTrie(self.db).TryGetBestLeftKeyAndValue() key, _, err := stateOrderList.getTrie(t.db).TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
return EmptyHash, Zero, err return EmptyHash, Zero, err
} }
orderId := common.BytesToHash(key) orderId := common.BytesToHash(key)
amount := stateOrderList.GetOrderAmount(self.db, orderId) amount := stateOrderList.GetOrderAmount(t.db, orderId)
return orderId, new(big.Int).SetBytes(amount.Bytes()), nil return orderId, new(big.Int).SetBytes(amount.Bytes()), nil
} }
return EmptyHash, Zero, fmt.Errorf("not found order list with orderBook : %s , price : %d , side :%s ", orderBook.Hex(), price, side) return EmptyHash, Zero, fmt.Errorf("not found order list with orderBook: %s , price : %d , side : %s", orderBook.Hex(), price, side)
} }
return EmptyHash, Zero, fmt.Errorf("not found orderBook : %s ", orderBook.Hex()) return EmptyHash, Zero, fmt.Errorf("not found orderBook: %s", orderBook.Hex())
} }
// updateStateExchangeObject writes the given object to the trie. // updateStateExchangeObject writes the given object to the trie.
func (self *TradingStateDB) updateStateExchangeObject(stateObject *tradingExchanges) { func (t *TradingStateDB) updateStateExchangeObject(stateObject *tradingExchanges) {
addr := stateObject.Hash() addr := stateObject.Hash()
data, err := rlp.EncodeToBytes(stateObject) data, err := rlp.EncodeToBytes(stateObject)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
} }
self.setError(self.trie.TryUpdate(addr[:], data)) t.setError(t.trie.TryUpdate(addr[:], data))
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObject *tradingExchanges) { func (t *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObject *tradingExchanges) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.stateExhangeObjects[addr]; obj != nil { if obj := t.stateExhangeObjects[addr]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.trie.TryGet(addr[:]) enc, err := t.trie.TryGet(addr[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) t.setError(err)
return nil return nil
} }
var data tradingExchangeObject var data tradingExchangeObject
@ -440,169 +442,169 @@ func (self *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObjec
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateExchanges(self, addr, data, self.MarkStateExchangeObjectDirty) obj := newStateExchanges(t, addr, data, t.MarkStateExchangeObjectDirty)
self.stateExhangeObjects[addr] = obj t.stateExhangeObjects[addr] = obj
return obj return obj
} }
func (self *TradingStateDB) setStateExchangeObject(object *tradingExchanges) { func (t *TradingStateDB) setStateExchangeObject(object *tradingExchanges) {
self.stateExhangeObjects[object.Hash()] = object t.stateExhangeObjects[object.Hash()] = object
self.stateExhangeObjectsDirty[object.Hash()] = struct{}{} t.stateExhangeObjectsDirty[object.Hash()] = struct{}{}
} }
// Retrieve a state object or create a new state object if nil. // Retrieve a state object or create a new state object if nil.
func (self *TradingStateDB) GetOrNewStateExchangeObject(addr common.Hash) *tradingExchanges { func (t *TradingStateDB) GetOrNewStateExchangeObject(addr common.Hash) *tradingExchanges {
stateExchangeObject := self.getStateExchangeObject(addr) stateExchangeObject := t.getStateExchangeObject(addr)
if stateExchangeObject == nil { if stateExchangeObject == nil {
stateExchangeObject = self.createExchangeObject(addr) stateExchangeObject = t.createExchangeObject(addr)
} }
return stateExchangeObject return stateExchangeObject
} }
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly // MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones. // state object cache iteration to find a handful of modified ones.
func (self *TradingStateDB) MarkStateExchangeObjectDirty(addr common.Hash) { func (t *TradingStateDB) MarkStateExchangeObjectDirty(addr common.Hash) {
self.stateExhangeObjectsDirty[addr] = struct{}{} t.stateExhangeObjectsDirty[addr] = struct{}{}
} }
// createStateOrderListObject creates a new state object. If there is an existing orderId with // createStateOrderListObject creates a new state object. If there is an existing orderId with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *TradingStateDB) createExchangeObject(hash common.Hash) (newobj *tradingExchanges) { func (t *TradingStateDB) createExchangeObject(hash common.Hash) (newobj *tradingExchanges) {
newobj = newStateExchanges(self, hash, tradingExchangeObject{LendingCount: Zero, MediumPrice: Zero, MediumPriceBeforeEpoch: Zero, TotalQuantity: Zero}, self.MarkStateExchangeObjectDirty) newobj = newStateExchanges(t, hash, tradingExchangeObject{LendingCount: Zero, MediumPrice: Zero, MediumPriceBeforeEpoch: Zero, TotalQuantity: Zero}, t.MarkStateExchangeObjectDirty)
newobj.setNonce(0) // sets the object to dirty newobj.setNonce(0) // sets the object to dirty
self.setStateExchangeObject(newobj) t.setStateExchangeObject(newobj)
return newobj return newobj
} }
// Copy creates a deep, independent copy of the state. // Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy. // Snapshots of the copied state cannot be applied to the copy.
func (self *TradingStateDB) Copy() *TradingStateDB { func (t *TradingStateDB) Copy() *TradingStateDB {
self.lock.Lock() t.lock.Lock()
defer self.lock.Unlock() defer t.lock.Unlock()
// Copy all the basic fields, initialize the memory ones // Copy all the basic fields, initialize the memory ones
state := &TradingStateDB{ state := &TradingStateDB{
db: self.db, db: t.db,
trie: self.db.CopyTrie(self.trie), trie: t.db.CopyTrie(t.trie),
stateExhangeObjects: make(map[common.Hash]*tradingExchanges, len(self.stateExhangeObjectsDirty)), stateExhangeObjects: make(map[common.Hash]*tradingExchanges, len(t.stateExhangeObjectsDirty)),
stateExhangeObjectsDirty: make(map[common.Hash]struct{}, len(self.stateExhangeObjectsDirty)), stateExhangeObjectsDirty: make(map[common.Hash]struct{}, len(t.stateExhangeObjectsDirty)),
} }
// Copy the dirty states, logs, and preimages // Copy the dirty states, logs, and preimages
for addr := range self.stateExhangeObjectsDirty { for addr := range t.stateExhangeObjectsDirty {
state.stateExhangeObjectsDirty[addr] = struct{}{} state.stateExhangeObjectsDirty[addr] = struct{}{}
} }
for addr, exchangeObject := range self.stateExhangeObjects { for addr, exchangeObject := range t.stateExhangeObjects {
state.stateExhangeObjects[addr] = exchangeObject.deepCopy(state, state.MarkStateExchangeObjectDirty) state.stateExhangeObjects[addr] = exchangeObject.deepCopy(state, state.MarkStateExchangeObjectDirty)
} }
return state return state
} }
func (s *TradingStateDB) clearJournalAndRefund() { func (t *TradingStateDB) clearJournalAndRefund() {
s.journal = nil t.journal = nil
s.validRevisions = s.validRevisions[:0] t.validRevisions = t.validRevisions[:0]
} }
// Snapshot returns an identifier for the current revision of the state. // Snapshot returns an identifier for the current revision of the state.
func (self *TradingStateDB) Snapshot() int { func (t *TradingStateDB) Snapshot() int {
id := self.nextRevisionId id := t.nextRevisionId
self.nextRevisionId++ t.nextRevisionId++
self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)}) t.validRevisions = append(t.validRevisions, revision{id, len(t.journal)})
return id return id
} }
// RevertToSnapshot reverts all state changes made since the given revision. // RevertToSnapshot reverts all state changes made since the given revision.
func (self *TradingStateDB) RevertToSnapshot(revid int) { func (t *TradingStateDB) RevertToSnapshot(revid int) {
// Find the snapshot in the stack of valid snapshots. // Find the snapshot in the stack of valid snapshots.
idx := sort.Search(len(self.validRevisions), func(i int) bool { idx := sort.Search(len(t.validRevisions), func(i int) bool {
return self.validRevisions[i].id >= revid return t.validRevisions[i].id >= revid
}) })
if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid { if idx == len(t.validRevisions) || t.validRevisions[idx].id != revid {
panic(fmt.Errorf("revision id %v cannot be reverted", revid)) panic(fmt.Errorf("revision id %v cannot be reverted", revid))
} }
snapshot := self.validRevisions[idx].journalIndex snapshot := t.validRevisions[idx].journalIndex
// Replay the journal to undo changes. // Replay the journal to undo changes.
for i := len(self.journal) - 1; i >= snapshot; i-- { for i := len(t.journal) - 1; i >= snapshot; i-- {
self.journal[i].undo(self) t.journal[i].undo(t)
} }
self.journal = self.journal[:snapshot] t.journal = t.journal[:snapshot]
// Remove invalidated snapshots from the stack. // Remove invalidated snapshots from the stack.
self.validRevisions = self.validRevisions[:idx] t.validRevisions = t.validRevisions[:idx]
} }
// Finalise finalises the state by removing the self destructed objects // Finalise finalises the state by removing the self destructed objects
// and clears the journal as well as the refunds. // and clears the journal as well as the refunds.
func (s *TradingStateDB) Finalise() { func (t *TradingStateDB) Finalise() {
// Commit objects to the trie. // Commit objects to the trie.
for addr, stateObject := range s.stateExhangeObjects { for addr, stateObject := range t.stateExhangeObjects {
if _, isDirty := s.stateExhangeObjectsDirty[addr]; isDirty { if _, isDirty := t.stateExhangeObjectsDirty[addr]; isDirty {
// Write any storage changes in the state object to its storage trie. // Write any storage changes in the state object to its storage trie.
err := stateObject.updateAsksRoot(s.db) err := stateObject.updateAsksRoot(t.db)
if err != nil { if err != nil {
log.Warn("Finalise updateAsksRoot", "err", err, "addr", addr, "stateObject", *stateObject) log.Warn("Finalise updateAsksRoot", "err", err, "addr", addr, "stateObject", *stateObject)
} }
stateObject.updateBidsRoot(s.db) stateObject.updateBidsRoot(t.db)
stateObject.updateOrdersRoot(s.db) stateObject.updateOrdersRoot(t.db)
stateObject.updateLiquidationPriceRoot(s.db) stateObject.updateLiquidationPriceRoot(t.db)
// Update the object in the main orderId trie. // Update the object in the main orderId trie.
s.updateStateExchangeObject(stateObject) t.updateStateExchangeObject(stateObject)
//delete(s.stateExhangeObjectsDirty, addr) //delete(s.stateExhangeObjectsDirty, addr)
} }
} }
s.clearJournalAndRefund() t.clearJournalAndRefund()
} }
// IntermediateRoot computes the current root orderBookHash of the state trie. // IntermediateRoot computes the current root orderBookHash of the state trie.
// It is called in between transactions to get the root orderBookHash that // It is called in between transactions to get the root orderBookHash that
// goes into transaction receipts. // goes into transaction receipts.
func (s *TradingStateDB) IntermediateRoot() common.Hash { func (t *TradingStateDB) IntermediateRoot() common.Hash {
s.Finalise() t.Finalise()
return s.trie.Hash() return t.trie.Hash()
} }
// Commit writes the state to the underlying in-memory trie database. // Commit writes the state to the underlying in-memory trie database.
func (s *TradingStateDB) Commit() (root common.Hash, err error) { func (t *TradingStateDB) Commit() (root common.Hash, err error) {
defer s.clearJournalAndRefund() defer t.clearJournalAndRefund()
// Commit objects to the trie. // Commit objects to the trie.
for addr, stateObject := range s.stateExhangeObjects { for addr, stateObject := range t.stateExhangeObjects {
if _, isDirty := s.stateExhangeObjectsDirty[addr]; isDirty { if _, isDirty := t.stateExhangeObjectsDirty[addr]; isDirty {
// Write any storage changes in the state object to its storage trie. // Write any storage changes in the state object to its storage trie.
if err := stateObject.CommitAsksTrie(s.db); err != nil { if err := stateObject.CommitAsksTrie(t.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitBidsTrie(s.db); err != nil { if err := stateObject.CommitBidsTrie(t.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitOrdersTrie(s.db); err != nil { if err := stateObject.CommitOrdersTrie(t.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitLiquidationPriceTrie(s.db); err != nil { if err := stateObject.CommitLiquidationPriceTrie(t.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
// Update the object in the main orderId trie. // Update the object in the main orderId trie.
s.updateStateExchangeObject(stateObject) t.updateStateExchangeObject(stateObject)
delete(s.stateExhangeObjectsDirty, addr) delete(t.stateExhangeObjectsDirty, addr)
} }
} }
// Write trie changes. // Write trie changes.
root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error { root, err = t.trie.Commit(func(leaf []byte, parent common.Hash) error {
var exchange tradingExchangeObject var exchange tradingExchangeObject
if err := rlp.DecodeBytes(leaf, &exchange); err != nil { if err := rlp.DecodeBytes(leaf, &exchange); err != nil {
return nil return nil
} }
if exchange.AskRoot != EmptyRoot { if exchange.AskRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.AskRoot, parent) t.db.TrieDB().Reference(exchange.AskRoot, parent)
} }
if exchange.BidRoot != EmptyRoot { if exchange.BidRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.BidRoot, parent) t.db.TrieDB().Reference(exchange.BidRoot, parent)
} }
if exchange.OrderRoot != EmptyRoot { if exchange.OrderRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.OrderRoot, parent) t.db.TrieDB().Reference(exchange.OrderRoot, parent)
} }
if exchange.LiquidationPriceRoot != EmptyRoot { if exchange.LiquidationPriceRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LiquidationPriceRoot, parent) t.db.TrieDB().Reference(exchange.LiquidationPriceRoot, parent)
} }
return nil return nil
}) })
@ -610,19 +612,19 @@ func (s *TradingStateDB) Commit() (root common.Hash, err error) {
return root, err return root, err
} }
func (self *TradingStateDB) GetAllLowerLiquidationPriceData(orderBook common.Hash, limit *big.Int) map[*big.Int]map[common.Hash][]common.Hash { func (t *TradingStateDB) GetAllLowerLiquidationPriceData(orderBook common.Hash, limit *big.Int) map[*big.Int]map[common.Hash][]common.Hash {
result := map[*big.Int]map[common.Hash][]common.Hash{} result := map[*big.Int]map[common.Hash][]common.Hash{}
orderbookState := self.getStateExchangeObject(orderBook) orderbookState := t.getStateExchangeObject(orderBook)
if orderbookState == nil { if orderbookState == nil {
return result return result
} }
mapPrices := orderbookState.getAllLowerLiquidationPrice(self.db, common.BigToHash(limit)) mapPrices := orderbookState.getAllLowerLiquidationPrice(t.db, common.BigToHash(limit))
for priceHash, liquidationState := range mapPrices { for priceHash, liquidationState := range mapPrices {
price := new(big.Int).SetBytes(priceHash[:]) price := new(big.Int).SetBytes(priceHash[:])
log.Debug("GetAllLowerLiquidationPriceData", "price", price, "limit", limit) log.Debug("GetAllLowerLiquidationPriceData", "price", price, "limit", limit)
if liquidationState != nil && price.Sign() > 0 && price.Cmp(limit) < 0 { if liquidationState != nil && price.Sign() > 0 && price.Cmp(limit) < 0 {
liquidationData := map[common.Hash][]common.Hash{} liquidationData := map[common.Hash][]common.Hash{}
priceLiquidationData := liquidationState.getAllLiquidationData(self.db) priceLiquidationData := liquidationState.getAllLiquidationData(t.db)
for lendingBook, data := range priceLiquidationData { for lendingBook, data := range priceLiquidationData {
if len(data) == 0 { if len(data) == 0 {
continue continue
@ -641,16 +643,16 @@ func (self *TradingStateDB) GetAllLowerLiquidationPriceData(orderBook common.Has
return result return result
} }
func (self *TradingStateDB) GetHighestLiquidationPriceData(orderBook common.Hash, price *big.Int) (*big.Int, map[common.Hash][]common.Hash) { func (t *TradingStateDB) GetHighestLiquidationPriceData(orderBook common.Hash, price *big.Int) (*big.Int, map[common.Hash][]common.Hash) {
liquidationData := map[common.Hash][]common.Hash{} liquidationData := map[common.Hash][]common.Hash{}
orderbookState := self.getStateExchangeObject(orderBook) orderbookState := t.getStateExchangeObject(orderBook)
if orderbookState == nil { if orderbookState == nil {
return common.Big0, liquidationData return common.Big0, liquidationData
} }
highestPriceHash, liquidationState := orderbookState.getHighestLiquidationPrice(self.db) highestPriceHash, liquidationState := orderbookState.getHighestLiquidationPrice(t.db)
highestPrice := new(big.Int).SetBytes(highestPriceHash[:]) highestPrice := new(big.Int).SetBytes(highestPriceHash[:])
if liquidationState != nil && highestPrice.Sign() > 0 && price.Cmp(highestPrice) < 0 { if liquidationState != nil && highestPrice.Sign() > 0 && price.Cmp(highestPrice) < 0 {
priceLiquidationData := liquidationState.getAllLiquidationData(self.db) priceLiquidationData := liquidationState.getAllLiquidationData(t.db)
for lendingBook, data := range priceLiquidationData { for lendingBook, data := range priceLiquidationData {
if len(data) == 0 { if len(data) == 0 {
continue continue
@ -667,26 +669,26 @@ func (self *TradingStateDB) GetHighestLiquidationPriceData(orderBook common.Hash
return highestPrice, liquidationData return highestPrice, liquidationData
} }
func (self *TradingStateDB) InsertLiquidationPrice(orderBook common.Hash, price *big.Int, lendingBook common.Hash, tradeId uint64) { func (t *TradingStateDB) InsertLiquidationPrice(orderBook common.Hash, price *big.Int, lendingBook common.Hash, tradeId uint64) {
tradIdHash := common.Uint64ToHash(tradeId) tradIdHash := common.Uint64ToHash(tradeId)
priceHash := common.BigToHash(price) priceHash := common.BigToHash(price)
orderBookState := self.getStateExchangeObject(orderBook) orderBookState := t.getStateExchangeObject(orderBook)
if orderBookState == nil { if orderBookState == nil {
orderBookState = self.createExchangeObject(orderBook) orderBookState = t.createExchangeObject(orderBook)
} }
liquidationPriceState := orderBookState.getStateLiquidationPrice(self.db, priceHash) liquidationPriceState := orderBookState.getStateLiquidationPrice(t.db, priceHash)
if liquidationPriceState == nil { if liquidationPriceState == nil {
liquidationPriceState = orderBookState.createStateLiquidationPrice(self.db, priceHash) liquidationPriceState = orderBookState.createStateLiquidationPrice(t.db, priceHash)
} }
lendingBookState := liquidationPriceState.getStateLendingBook(self.db, lendingBook) lendingBookState := liquidationPriceState.getStateLendingBook(t.db, lendingBook)
if lendingBookState == nil { if lendingBookState == nil {
lendingBookState = liquidationPriceState.createLendingBook(self.db, lendingBook) lendingBookState = liquidationPriceState.createLendingBook(t.db, lendingBook)
} }
lendingBookState.insertTradingId(self.db, tradIdHash) lendingBookState.insertTradingId(t.db, tradIdHash)
lendingBookState.AddVolume(One) lendingBookState.AddVolume(One)
liquidationPriceState.AddVolume(One) liquidationPriceState.AddVolume(One)
orderBookState.addLendingCount(One) orderBookState.addLendingCount(One)
self.journal = append(self.journal, insertLiquidationPrice{ t.journal = append(t.journal, insertLiquidationPrice{
orderBook: orderBook, orderBook: orderBook,
price: price, price: price,
lendingBook: lendingBook, lendingBook: lendingBook,
@ -694,35 +696,35 @@ func (self *TradingStateDB) InsertLiquidationPrice(orderBook common.Hash, price
}) })
} }
func (self *TradingStateDB) RemoveLiquidationPrice(orderBook common.Hash, price *big.Int, lendingBook common.Hash, tradeId uint64) error { func (t *TradingStateDB) RemoveLiquidationPrice(orderBook common.Hash, price *big.Int, lendingBook common.Hash, tradeId uint64) error {
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
priceHash := common.BigToHash(price) priceHash := common.BigToHash(price)
orderbookState := self.getStateExchangeObject(orderBook) orderbookState := t.getStateExchangeObject(orderBook)
if orderbookState == nil { if orderbookState == nil {
return fmt.Errorf("order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found order book: %s", orderBook.Hex())
} }
liquidationPriceState := orderbookState.getStateLiquidationPrice(self.db, priceHash) liquidationPriceState := orderbookState.getStateLiquidationPrice(t.db, priceHash)
if liquidationPriceState == nil { if liquidationPriceState == nil {
return fmt.Errorf("liquidation price not found : %s , %s ", orderBook.Hex(), priceHash.Hex()) return fmt.Errorf("not found liquidation price: %s , %s", orderBook.Hex(), priceHash.Hex())
} }
lendingBookState := liquidationPriceState.getStateLendingBook(self.db, lendingBook) lendingBookState := liquidationPriceState.getStateLendingBook(t.db, lendingBook)
if lendingBookState == nil { if lendingBookState == nil {
return fmt.Errorf("lending book not found : %s , %s ,%s ", orderBook.Hex(), priceHash.Hex(), lendingBook.Hex()) return fmt.Errorf("not found lending book: %s , %s ,%s", orderBook.Hex(), priceHash.Hex(), lendingBook.Hex())
} }
if !lendingBookState.Exist(self.db, tradeIdHash) { if !lendingBookState.Exist(t.db, tradeIdHash) {
return fmt.Errorf("trade id not found : %s , %s ,%s , %d ", orderBook.Hex(), priceHash.Hex(), lendingBook.Hex(), tradeId) return fmt.Errorf("not found trade id: %s, %s ,%s , %d", orderBook.Hex(), priceHash.Hex(), lendingBook.Hex(), tradeId)
} }
lendingBookState.removeTradingId(self.db, tradeIdHash) lendingBookState.removeTradingId(t.db, tradeIdHash)
lendingBookState.subVolume(One) lendingBookState.subVolume(One)
liquidationPriceState.subVolume(One) liquidationPriceState.subVolume(One)
if liquidationPriceState.Volume().Sign() == 0 { if liquidationPriceState.Volume().Sign() == 0 {
err := orderbookState.getLiquidationPriceTrie(self.db).TryDelete(priceHash[:]) err := orderbookState.getLiquidationPriceTrie(t.db).TryDelete(priceHash[:])
if err != nil { if err != nil {
log.Warn("RemoveLiquidationPrice getLiquidationPriceTrie.TryDelete", "err", err, "priceHash", priceHash[:]) log.Warn("RemoveLiquidationPrice getLiquidationPriceTrie.TryDelete", "err", err, "priceHash", priceHash[:])
} }
} }
orderbookState.subLendingCount(One) orderbookState.subLendingCount(One)
self.journal = append(self.journal, removeLiquidationPrice{ t.journal = append(t.journal, removeLiquidationPrice{
orderBook: orderBook, orderBook: orderBook,
price: price, price: price,
lendingBook: lendingBook, lendingBook: lendingBook,

View file

@ -5,8 +5,8 @@ import (
"time" "time"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/globalsign/mgo/bson" "github.com/globalsign/mgo/bson"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -136,7 +136,7 @@ func (t *Trade) SetBSON(raw bson.Raw) error {
// The OrderHash, Amount, Taker and TradeNonce attributes must be // The OrderHash, Amount, Taker and TradeNonce attributes must be
// set before attempting to compute the trade orderBookHash // set before attempting to compute the trade orderBookHash
func (t *Trade) ComputeHash() common.Hash { func (t *Trade) ComputeHash() common.Hash {
sha := sha3.NewKeccak256() sha := sha3.NewLegacyKeccak256()
sha.Write(t.MakerOrderHash.Bytes()) sha.Write(t.MakerOrderHash.Bytes())
sha.Write(t.TakerOrderHash.Bytes()) sha.Write(t.TakerOrderHash.Bytes())
return common.BytesToHash(sha.Sum(nil)) return common.BytesToHash(sha.Sum(nil))

View file

@ -8,10 +8,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
lru "github.com/hashicorp/golang-lru"
) )
type BatchItem struct { type BatchItem struct {
@ -21,7 +19,6 @@ type BatchItem struct {
type BatchDatabase struct { type BatchDatabase struct {
db ethdb.Database db ethdb.Database
emptyKey []byte emptyKey []byte
cacheItems *lru.Cache // Cache for reading
lock sync.RWMutex lock sync.RWMutex
cacheLimit int cacheLimit int
Debug bool Debug bool
@ -44,11 +41,8 @@ func NewBatchDatabaseWithEncode(datadir string, cacheLimit int) *BatchDatabase {
itemCacheLimit = cacheLimit itemCacheLimit = cacheLimit
} }
cacheItems, _ := lru.New(itemCacheLimit)
batchDB := &BatchDatabase{ batchDB := &BatchDatabase{
db: db, db: db,
cacheItems: cacheItems,
emptyKey: EmptyKey(), // pre alloc for comparison emptyKey: EmptyKey(), // pre alloc for comparison
cacheLimit: itemCacheLimit, cacheLimit: itemCacheLimit,
} }

View file

@ -10,11 +10,11 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate" "github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/globalsign/mgo" "github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson" "github.com/globalsign/mgo/bson"
lru "github.com/hashicorp/golang-lru"
) )
const ( const (
@ -32,7 +32,7 @@ type MongoDatabase struct {
Session *mgo.Session Session *mgo.Session
dbName string dbName string
emptyKey []byte emptyKey []byte
cacheItems *lru.Cache // Cache for reading cacheItems *lru.Cache[string, interface{}] // Cache for reading
orderBulk *mgo.Bulk orderBulk *mgo.Bulk
tradeBulk *mgo.Bulk tradeBulk *mgo.Bulk
epochPriceBulk *mgo.Bulk epochPriceBulk *mgo.Bulk
@ -64,12 +64,11 @@ func NewMongoDatabase(session *mgo.Session, dbName string, mongoURL string, repl
if cacheLimit > 0 { if cacheLimit > 0 {
itemCacheLimit = cacheLimit itemCacheLimit = cacheLimit
} }
cacheItems, _ := lru.New(itemCacheLimit)
db := &MongoDatabase{ db := &MongoDatabase{
Session: session, Session: session,
dbName: dbName, dbName: dbName,
cacheItems: cacheItems, cacheItems: lru.NewCache[string, interface{}](itemCacheLimit),
} }
if err := db.EnsureIndexes(); err != nil { if err := db.EnsureIndexes(); err != nil {
return nil, err return nil, err
@ -101,7 +100,7 @@ func (db *MongoDatabase) HasObject(hash common.Hash, val interface{}) (bool, err
err error err error
) )
query := bson.M{"hash": hash.Hex()} query := bson.M{"hash": hash.Hex()}
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
// Find key in ordersCollection collection // Find key in ordersCollection collection
count, err = sc.DB(db.dbName).C(ordersCollection).Find(query).Limit(1).Count() count, err = sc.DB(db.dbName).C(ordersCollection).Find(query).Limit(1).Count()
@ -126,7 +125,6 @@ func (db *MongoDatabase) HasObject(hash common.Hash, val interface{}) (bool, err
} }
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
// Find key in lendingItemsCollection collection // Find key in lendingItemsCollection collection
item := val.(*lendingstate.LendingItem)
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
count, err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).Limit(1).Count() count, err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).Limit(1).Count()
@ -176,7 +174,7 @@ func (db *MongoDatabase) GetObject(hash common.Hash, val interface{}) (interface
query := bson.M{"hash": hash.Hex()} query := bson.M{"hash": hash.Hex()}
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
var oi *tradingstate.OrderItem var oi *tradingstate.OrderItem
err := sc.DB(db.dbName).C(ordersCollection).Find(query).One(&oi) err := sc.DB(db.dbName).C(ordersCollection).Find(query).One(&oi)
@ -196,7 +194,6 @@ func (db *MongoDatabase) GetObject(hash common.Hash, val interface{}) (interface
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
var li *lendingstate.LendingItem var li *lendingstate.LendingItem
var err error var err error
item := val.(*lendingstate.LendingItem)
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).One(&li) err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).One(&li)
@ -230,62 +227,58 @@ func (db *MongoDatabase) PutObject(hash common.Hash, val interface{}) error {
cacheKey := db.getCacheKey(hash.Bytes()) cacheKey := db.getCacheKey(hash.Bytes())
db.cacheItems.Add(cacheKey, val) db.cacheItems.Add(cacheKey, val)
switch val.(type) { switch item := val.(type) {
case *tradingstate.Trade: case *tradingstate.Trade:
// PutObject trade into tradesCollection collection // PutObject trade into tradesCollection collection
db.tradeBulk.Insert(val.(*tradingstate.Trade)) db.tradeBulk.Insert(item)
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
// PutObject order into ordersCollection collection // PutObject order into ordersCollection collection
o := val.(*tradingstate.OrderItem) if item.Status == tradingstate.OrderStatusOpen {
if o.Status == tradingstate.OrderStatusOpen { db.orderBulk.Insert(item)
db.orderBulk.Insert(o)
} else { } else {
query := bson.M{"hash": o.Hash.Hex()} query := bson.M{"hash": item.Hash.Hex()}
db.orderBulk.Upsert(query, o) db.orderBulk.Upsert(query, item)
} }
return nil return nil
case *tradingstate.EpochPriceItem: case *tradingstate.EpochPriceItem:
item := val.(*tradingstate.EpochPriceItem)
query := bson.M{"hash": item.Hash.Hex()} query := bson.M{"hash": item.Hash.Hex()}
db.epochPriceBulk.Upsert(query, item) db.epochPriceBulk.Upsert(query, item)
return nil return nil
case *lendingstate.LendingTrade: case *lendingstate.LendingTrade:
lt := val.(*lendingstate.LendingTrade)
// PutObject LendingTrade into tradesCollection collection // PutObject LendingTrade into tradesCollection collection
if existed, err := db.HasObject(hash, val); err == nil && existed { if existed, err := db.HasObject(hash, val); err == nil && existed {
query := bson.M{"hash": lt.Hash.Hex()} query := bson.M{"hash": item.Hash.Hex()}
db.lendingTradeBulk.Upsert(query, lt) db.lendingTradeBulk.Upsert(query, item)
} else { } else {
db.lendingTradeBulk.Insert(lt) db.lendingTradeBulk.Insert(item)
} }
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
// PutObject order into ordersCollection collection // PutObject order into ordersCollection collection
li := val.(*lendingstate.LendingItem) switch item.Type {
switch li.Type {
case lendingstate.Repay: case lendingstate.Repay:
if li.Status != lendingstate.LendingStatusReject { if item.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.Repay item.Status = lendingstate.Repay
} }
db.repayBulk.Insert(li) db.repayBulk.Insert(item)
return nil return nil
case lendingstate.TopUp: case lendingstate.TopUp:
if li.Status != lendingstate.LendingStatusReject { if item.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.TopUp item.Status = lendingstate.TopUp
} }
db.topUpBulk.Insert(li) db.topUpBulk.Insert(item)
return nil return nil
case lendingstate.Recall: case lendingstate.Recall:
if li.Status != lendingstate.LendingStatusReject { if item.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.Recall item.Status = lendingstate.Recall
} }
db.recallBulk.Insert(li) db.recallBulk.Insert(item)
return nil return nil
default: default:
if li.Status == lendingstate.LendingStatusOpen { if item.Status == lendingstate.LendingStatusOpen {
db.lendingItemBulk.Insert(li) db.lendingItemBulk.Insert(item)
} else { } else {
query := bson.M{"hash": li.Hash.Hex()} query := bson.M{"hash": item.Hash.Hex()}
db.lendingItemBulk.Upsert(query, li) db.lendingItemBulk.Upsert(query, item)
} }
return nil return nil
} }
@ -313,7 +306,7 @@ func (db *MongoDatabase) DeleteObject(hash common.Hash, val interface{}) error {
if found { if found {
var err error var err error
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
err = sc.DB(db.dbName).C(ordersCollection).Remove(query) err = sc.DB(db.dbName).C(ordersCollection).Remove(query)
if err != nil && err != mgo.ErrNotFound { if err != nil && err != mgo.ErrNotFound {
@ -325,7 +318,6 @@ func (db *MongoDatabase) DeleteObject(hash common.Hash, val interface{}) error {
return fmt.Errorf("failed to delete XDCx trade. Err: %v", err) return fmt.Errorf("failed to delete XDCx trade. Err: %v", err)
} }
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
err = sc.DB(db.dbName).C(lendingRepayCollection).Remove(query) err = sc.DB(db.dbName).C(lendingRepayCollection).Remove(query)
@ -424,7 +416,7 @@ func (db *MongoDatabase) DeleteItemByTxHash(txhash common.Hash, val interface{})
defer sc.Close() defer sc.Close()
query := bson.M{"txHash": txhash.Hex()} query := bson.M{"txHash": txhash.Hex()}
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
if err := sc.DB(db.dbName).C(ordersCollection).Remove(query); err != nil && err != mgo.ErrNotFound { if err := sc.DB(db.dbName).C(ordersCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete order", "txhash", txhash, "err", err) log.Error("DeleteItemByTxHash: failed to delete order", "txhash", txhash, "err", err)
@ -434,7 +426,6 @@ func (db *MongoDatabase) DeleteItemByTxHash(txhash common.Hash, val interface{})
log.Error("DeleteItemByTxHash: failed to delete trade", "txhash", txhash, "err", err) log.Error("DeleteItemByTxHash: failed to delete trade", "txhash", txhash, "err", err)
} }
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
if err := sc.DB(db.dbName).C(lendingRepayCollection).Remove(query); err != nil && err != mgo.ErrNotFound { if err := sc.DB(db.dbName).C(lendingRepayCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
@ -473,7 +464,7 @@ func (db *MongoDatabase) GetListItemByTxHash(txhash common.Hash, val interface{}
defer sc.Close() defer sc.Close()
query := bson.M{"txHash": txhash.Hex()} query := bson.M{"txHash": txhash.Hex()}
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
result := []*tradingstate.OrderItem{} result := []*tradingstate.OrderItem{}
if err := sc.DB(db.dbName).C(ordersCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound { if err := sc.DB(db.dbName).C(ordersCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
@ -487,7 +478,6 @@ func (db *MongoDatabase) GetListItemByTxHash(txhash common.Hash, val interface{}
} }
return result return result
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
result := []*lendingstate.LendingItem{} result := []*lendingstate.LendingItem{}
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
@ -529,7 +519,7 @@ func (db *MongoDatabase) GetListItemByHashes(hashes []string, val interface{}) i
query := bson.M{"hash": bson.M{"$in": hashes}} query := bson.M{"hash": bson.M{"$in": hashes}}
switch val.(type) { switch item := val.(type) {
case *tradingstate.OrderItem: case *tradingstate.OrderItem:
result := []*tradingstate.OrderItem{} result := []*tradingstate.OrderItem{}
if err := sc.DB(db.dbName).C(ordersCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound { if err := sc.DB(db.dbName).C(ordersCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
@ -543,7 +533,6 @@ func (db *MongoDatabase) GetListItemByHashes(hashes []string, val interface{}) i
} }
return result return result
case *lendingstate.LendingItem: case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
result := []*lendingstate.LendingItem{} result := []*lendingstate.LendingItem{}
switch item.Type { switch item.Type {
case lendingstate.Repay: case lendingstate.Repay:
@ -835,7 +824,10 @@ func (db *MongoDatabase) EnsureIndexes() error {
} }
func (db *MongoDatabase) Close() error { func (db *MongoDatabase) Close() error {
return db.Close() if db.Session != nil {
db.Session.Close()
}
return nil
} }
// HasAncient returns an error as we don't have a backing chain freezer. // HasAncient returns an error as we don't have a backing chain freezer.

View file

@ -13,6 +13,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCxDAO" "github.com/XinFinOrg/XDPoSChain/XDCxDAO"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate" "github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/common/prque" "github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
@ -20,7 +21,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/p2p" "github.com/XinFinOrg/XDPoSChain/p2p"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
lru "github.com/hashicorp/golang-lru"
) )
const ( const (
@ -42,8 +42,8 @@ type Lending struct {
orderNonce map[common.Address]*big.Int orderNonce map[common.Address]*big.Int
XDCx *XDCx.XDCX XDCx *XDCx.XDCX
lendingItemHistory *lru.Cache lendingItemHistory *lru.Cache[common.Hash, map[common.Hash]lendingstate.LendingItemHistoryItem]
lendingTradeHistory *lru.Cache lendingTradeHistory *lru.Cache[common.Hash, map[common.Hash]lendingstate.LendingTradeHistoryItem]
} }
func (l *Lending) Protocols() []p2p.Protocol { func (l *Lending) Protocols() []p2p.Protocol {
@ -62,13 +62,11 @@ func (l *Lending) Stop() error {
} }
func New(XDCx *XDCx.XDCX) *Lending { func New(XDCx *XDCx.XDCX) *Lending {
itemCache, _ := lru.New(defaultCacheLimit)
lendingTradeCache, _ := lru.New(defaultCacheLimit)
lending := &Lending{ lending := &Lending{
orderNonce: make(map[common.Address]*big.Int), orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil), Triegc: prque.New(nil),
lendingItemHistory: itemCache, lendingItemHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingItemHistoryItem](defaultCacheLimit),
lendingTradeHistory: lendingTradeCache, lendingTradeHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingTradeHistoryItem](defaultCacheLimit),
} }
lending.StateCache = lendingstate.NewDatabase(XDCx.GetLevelDB()) lending.StateCache = lendingstate.NewDatabase(XDCx.GetLevelDB())
lending.XDCx = XDCx lending.XDCx = XDCx
@ -311,7 +309,7 @@ func (l *Lending) SyncDataToSDKNode(chain consensus.ChainContext, statedb *state
} }
// maker dirty order // maker dirty order
makerFilledAmount := big.NewInt(0) makerFilledAmount := big.NewInt(0)
makerOrderHash := common.Hash{} var makerOrderHash common.Hash
if updatedTakerLendingItem.Side == lendingstate.Borrowing { if updatedTakerLendingItem.Side == lendingstate.Borrowing {
makerOrderHash = tradeRecord.InvestingOrderHash makerOrderHash = tradeRecord.InvestingOrderHash
} else { } else {
@ -665,7 +663,7 @@ func (l *Lending) GetLendingState(block *types.Block, author common.Address) (*l
return nil, err return nil, err
} }
if l.StateCache == nil { if l.StateCache == nil {
return nil, errors.New("Not initialized XDCx") return nil, errors.New("not initialized XDCx")
} }
state, err := lendingstate.New(root, l.StateCache) state, err := lendingstate.New(root, l.StateCache)
if err != nil { if err != nil {
@ -684,10 +682,7 @@ func (l *Lending) HasLendingState(block *types.Block, author common.Address) boo
return false return false
} }
_, err = l.StateCache.OpenTrie(root) _, err = l.StateCache.OpenTrie(root)
if err != nil { return err == nil
return false
}
return true
} }
func (l *Lending) GetTriegc() *prque.Prque { func (l *Lending) GetTriegc() *prque.Prque {
@ -708,12 +703,9 @@ func (l *Lending) GetLendingStateRoot(block *types.Block, author common.Address)
} }
func (l *Lending) UpdateLendingItemCache(LendingToken, CollateralToken common.Address, hash common.Hash, txhash common.Hash, lastState lendingstate.LendingItemHistoryItem) { func (l *Lending) UpdateLendingItemCache(LendingToken, CollateralToken common.Address, hash common.Hash, txhash common.Hash, lastState lendingstate.LendingItemHistoryItem) {
var lendingCacheAtTxHash map[common.Hash]lendingstate.LendingItemHistoryItem lendingCacheAtTxHash, ok := l.lendingItemHistory.Get(txhash)
c, ok := l.lendingItemHistory.Get(txhash) if !ok || lendingCacheAtTxHash == nil {
if !ok || c == nil {
lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingItemHistoryItem) lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingItemHistoryItem)
} else {
lendingCacheAtTxHash = c.(map[common.Hash]lendingstate.LendingItemHistoryItem)
} }
orderKey := lendingstate.GetLendingItemHistoryKey(LendingToken, CollateralToken, hash) orderKey := lendingstate.GetLendingItemHistoryKey(LendingToken, CollateralToken, hash)
_, ok = lendingCacheAtTxHash[orderKey] _, ok = lendingCacheAtTxHash[orderKey]
@ -725,11 +717,9 @@ func (l *Lending) UpdateLendingItemCache(LendingToken, CollateralToken common.Ad
func (l *Lending) UpdateLendingTradeCache(hash common.Hash, txhash common.Hash, lastState lendingstate.LendingTradeHistoryItem) { func (l *Lending) UpdateLendingTradeCache(hash common.Hash, txhash common.Hash, lastState lendingstate.LendingTradeHistoryItem) {
var lendingCacheAtTxHash map[common.Hash]lendingstate.LendingTradeHistoryItem var lendingCacheAtTxHash map[common.Hash]lendingstate.LendingTradeHistoryItem
c, ok := l.lendingTradeHistory.Get(txhash) lendingCacheAtTxHash, ok := l.lendingTradeHistory.Get(txhash)
if !ok || c == nil { if !ok || lendingCacheAtTxHash == nil {
lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingTradeHistoryItem) lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingTradeHistoryItem)
} else {
lendingCacheAtTxHash = c.(map[common.Hash]lendingstate.LendingTradeHistoryItem)
} }
_, ok = lendingCacheAtTxHash[hash] _, ok = lendingCacheAtTxHash[hash]
if !ok { if !ok {
@ -746,16 +736,15 @@ func (l *Lending) RollbackLendingData(txhash common.Hash) error {
items := db.GetListItemByTxHash(txhash, &lendingstate.LendingItem{}) items := db.GetListItemByTxHash(txhash, &lendingstate.LendingItem{})
if items != nil { if items != nil {
for _, item := range items.([]*lendingstate.LendingItem) { for _, item := range items.([]*lendingstate.LendingItem) {
c, ok := l.lendingItemHistory.Get(txhash) cacheAtTxHash, ok := l.lendingItemHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback lendingItem", "txhash", txhash.Hex(), "item", lendingstate.ToJSON(item), "lendingItemHistory", c) log.Debug("XDCxlending reorg: rollback lendingItem", "txhash", txhash.Hex(), "item", lendingstate.ToJSON(item), "lendingItemHistory", cacheAtTxHash)
if !ok { if !ok || cacheAtTxHash == nil {
log.Debug("XDCxlending reorg: remove item due to no lendingItemHistory", "item", lendingstate.ToJSON(item)) log.Debug("XDCxlending reorg: remove item due to no lendingItemHistory", "item", lendingstate.ToJSON(item))
if err := db.DeleteObject(item.Hash, &lendingstate.LendingItem{}); err != nil { if err := db.DeleteObject(item.Hash, &lendingstate.LendingItem{}); err != nil {
return fmt.Errorf("failed to remove reorg LendingItem. Err: %v . Item: %s", err.Error(), lendingstate.ToJSON(item)) return fmt.Errorf("failed to remove reorg LendingItem. Err: %v . Item: %s", err.Error(), lendingstate.ToJSON(item))
} }
continue continue
} }
cacheAtTxHash := c.(map[common.Hash]lendingstate.LendingItemHistoryItem)
lendingItemHistory := cacheAtTxHash[lendingstate.GetLendingItemHistoryKey(item.LendingToken, item.CollateralToken, item.Hash)] lendingItemHistory := cacheAtTxHash[lendingstate.GetLendingItemHistoryKey(item.LendingToken, item.CollateralToken, item.Hash)]
if (lendingItemHistory == lendingstate.LendingItemHistoryItem{}) { if (lendingItemHistory == lendingstate.LendingItemHistoryItem{}) {
log.Debug("XDCxlending reorg: remove item due to empty lendingItemHistory", "item", lendingstate.ToJSON(item)) log.Debug("XDCxlending reorg: remove item due to empty lendingItemHistory", "item", lendingstate.ToJSON(item))
@ -779,16 +768,15 @@ func (l *Lending) RollbackLendingData(txhash common.Hash) error {
items = db.GetListItemByTxHash(txhash, &lendingstate.LendingTrade{}) items = db.GetListItemByTxHash(txhash, &lendingstate.LendingTrade{})
if items != nil { if items != nil {
for _, trade := range items.([]*lendingstate.LendingTrade) { for _, trade := range items.([]*lendingstate.LendingTrade) {
c, ok := l.lendingTradeHistory.Get(txhash) cacheAtTxHash, ok := l.lendingTradeHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback LendingTrade", "txhash", txhash.Hex(), "trade", lendingstate.ToJSON(trade), "LendingTradeHistory", c) log.Debug("XDCxlending reorg: rollback LendingTrade", "txhash", txhash.Hex(), "trade", lendingstate.ToJSON(trade), "LendingTradeHistory", cacheAtTxHash)
if !ok { if !ok || cacheAtTxHash == nil {
log.Debug("XDCxlending reorg: remove trade due to no LendingTradeHistory", "trade", lendingstate.ToJSON(trade)) log.Debug("XDCxlending reorg: remove trade due to no LendingTradeHistory", "trade", lendingstate.ToJSON(trade))
if err := db.DeleteObject(trade.Hash, &lendingstate.LendingTrade{}); err != nil { if err := db.DeleteObject(trade.Hash, &lendingstate.LendingTrade{}); err != nil {
return fmt.Errorf("failed to remove reorg LendingTrade. Err: %v . Trade: %s", err.Error(), lendingstate.ToJSON(trade)) return fmt.Errorf("failed to remove reorg LendingTrade. Err: %v . Trade: %s", err.Error(), lendingstate.ToJSON(trade))
} }
continue continue
} }
cacheAtTxHash := c.(map[common.Hash]lendingstate.LendingTradeHistoryItem)
lendingTradeHistoryItem := cacheAtTxHash[trade.Hash] lendingTradeHistoryItem := cacheAtTxHash[trade.Hash]
if (lendingTradeHistoryItem == lendingstate.LendingTradeHistoryItem{}) { if (lendingTradeHistoryItem == lendingstate.LendingTradeHistoryItem{}) {
log.Debug("XDCxlending reorg: remove trade due to empty LendingTradeHistory", "trade", lendingstate.ToJSON(trade)) log.Debug("XDCxlending reorg: remove trade due to empty LendingTradeHistory", "trade", lendingstate.ToJSON(trade))
@ -926,7 +914,7 @@ func (l *Lending) ProcessLiquidationData(header *types.Header, chain consensus.C
trade := lendingState.GetLendingTrade(lendingBook, tradingIdHash) trade := lendingState.GetLendingTrade(lendingBook, tradingIdHash)
log.Debug("TestRecall", "borrower", trade.Borrower.Hex(), "lendingToken", trade.LendingToken.Hex(), "collateral", trade.CollateralToken.Hex(), "price", price, "tradingIdHash", tradingIdHash.Hex()) log.Debug("TestRecall", "borrower", trade.Borrower.Hex(), "lendingToken", trade.LendingToken.Hex(), "collateral", trade.CollateralToken.Hex(), "price", price, "tradingIdHash", tradingIdHash.Hex())
if trade.AutoTopUp { if trade.AutoTopUp {
err, _, newTrade := l.ProcessRecallLendingTrade(lendingState, statedb, tradingState, lendingBook, tradingIdHash, newLiquidatePrice) _, newTrade, err := l.ProcessRecallLendingTrade(lendingState, statedb, tradingState, lendingBook, tradingIdHash, newLiquidatePrice)
if err != nil { if err != nil {
log.Error("ProcessRecallLendingTrade", "lendingBook", lendingBook.Hex(), "tradingIdHash", tradingIdHash.Hex(), "newLiquidatePrice", newLiquidatePrice, "err", err) log.Error("ProcessRecallLendingTrade", "lendingBook", lendingBook.Hex(), "tradingIdHash", tradingIdHash.Hex(), "newLiquidatePrice", newLiquidatePrice, "err", err)
return updatedTrades, liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades, err return updatedTrades, liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades, err

View file

@ -23,7 +23,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
) )
// Trie cache generation limit after which to evic trie nodes from memory. // Trie cache generation limit after which to evic trie nodes from memory.
@ -33,9 +32,6 @@ const (
// Number of past tries to keep. This value is chosen such that // Number of past tries to keep. This value is chosen such that
// reasonable chain reorg depths will hit an existing trie. // reasonable chain reorg depths will hit an existing trie.
maxPastTries = 12 maxPastTries = 12
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
) )
// Database wraps access to tries and contract code. // Database wraps access to tries and contract code.
@ -78,18 +74,16 @@ type Trie interface {
// intermediate trie-node memory pool between the low level storage layer and the // intermediate trie-node memory pool between the low level storage layer and the
// high level trie abstraction. // high level trie abstraction.
func NewDatabase(db ethdb.Database) Database { func NewDatabase(db ethdb.Database) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{ return &cachingDB{
db: trie.NewDatabase(db), db: trie.NewDatabase(db),
codeSizeCache: csc, // codeSizeCache: csc,
} }
} }
type cachingDB struct { type cachingDB struct {
db *trie.Database db *trie.Database
mu sync.Mutex mu sync.Mutex
pastTries []*XDCXTrie pastTries []*XDCXTrie
codeSizeCache *lru.Cache
} }
// OpenTrie opens the main account trie. // OpenTrie opens the main account trie.

View file

@ -18,11 +18,11 @@ package lendingstate
import ( import (
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/rlp"
"math/big" "math/big"
"sort" "sort"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
) )
@ -39,13 +39,13 @@ type DumpOrderBookInfo struct {
LowestLiquidationTime *big.Int LowestLiquidationTime *big.Int
} }
func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) { func (ls *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpOrderList{} mapResult := map[*big.Int]DumpOrderList{}
it := trie.NewIterator(exhangeObject.getInvestingTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
interestHash := common.BytesToHash(it.Key) interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) { if common.EmptyHash(interestHash) {
@ -57,15 +57,15 @@ func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.I
} else { } else {
var data itemList var data itemList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,interest :%v ", orderBook.Hex(), interest) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , interest : %v", orderBook.Hex(), interest)
} }
stateOrderList := newItemListState(orderBook, interestHash, data, nil) stateOrderList := newItemListState(orderBook, interestHash, data, nil)
mapResult[interest] = stateOrderList.DumpItemList(self.db) mapResult[interest] = stateOrderList.DumpItemList(ls.db)
} }
} }
for interestHash, itemList := range exhangeObject.investingStates { for interestHash, itemList := range exhangeObject.investingStates {
if itemList.Volume().Sign() > 0 { if itemList.Volume().Sign() > 0 {
mapResult[new(big.Int).SetBytes(interestHash.Bytes())] = itemList.DumpItemList(self.db) mapResult[new(big.Int).SetBytes(interestHash.Bytes())] = itemList.DumpItemList(ls.db)
} }
} }
listInterest := []*big.Int{} listInterest := []*big.Int{}
@ -82,13 +82,13 @@ func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.I
return result, nil return result, nil
} }
func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) { func (ls *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpOrderList{} mapResult := map[*big.Int]DumpOrderList{}
it := trie.NewIterator(exhangeObject.getBorrowingTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
interestHash := common.BytesToHash(it.Key) interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) { if common.EmptyHash(interestHash) {
@ -100,15 +100,15 @@ func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.I
} else { } else {
var data itemList var data itemList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,interest :%v ", orderBook.Hex(), interest) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , interest : %v", orderBook.Hex(), interest)
} }
stateOrderList := newItemListState(orderBook, interestHash, data, nil) stateOrderList := newItemListState(orderBook, interestHash, data, nil)
mapResult[interest] = stateOrderList.DumpItemList(self.db) mapResult[interest] = stateOrderList.DumpItemList(ls.db)
} }
} }
for interestHash, itemList := range exhangeObject.borrowingStates { for interestHash, itemList := range exhangeObject.borrowingStates {
if itemList.Volume().Sign() > 0 { if itemList.Volume().Sign() > 0 {
mapResult[new(big.Int).SetBytes(interestHash.Bytes())] = itemList.DumpItemList(self.db) mapResult[new(big.Int).SetBytes(interestHash.Bytes())] = itemList.DumpItemList(ls.db)
} }
} }
listInterest := []*big.Int{} listInterest := []*big.Int{}
@ -125,13 +125,13 @@ func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.I
return result, nil return result, nil
} }
func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*big.Int, error) { func (ls *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]*big.Int{} mapResult := map[*big.Int]*big.Int{}
it := trie.NewIterator(exhangeObject.getInvestingTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
interestHash := common.BytesToHash(it.Key) interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) { if common.EmptyHash(interestHash) {
@ -143,7 +143,7 @@ func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*
} else { } else {
var data itemList var data itemList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,interest :%v ", orderBook.Hex(), interest) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , interest : %v", orderBook.Hex(), interest)
} }
stateOrderList := newItemListState(orderBook, interestHash, data, nil) stateOrderList := newItemListState(orderBook, interestHash, data, nil)
mapResult[interest] = stateOrderList.data.Volume mapResult[interest] = stateOrderList.data.Volume
@ -168,13 +168,13 @@ func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*
return result, nil return result, nil
} }
func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*big.Int, error) { func (ls *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]*big.Int{} mapResult := map[*big.Int]*big.Int{}
it := trie.NewIterator(exhangeObject.getBorrowingTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
interestHash := common.BytesToHash(it.Key) interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) { if common.EmptyHash(interestHash) {
@ -186,7 +186,7 @@ func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*
} else { } else {
var data itemList var data itemList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,interest :%v ", orderBook.Hex(), interest) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , interest : %v", orderBook.Hex(), interest)
} }
stateOrderList := newItemListState(orderBook, interestHash, data, nil) stateOrderList := newItemListState(orderBook, interestHash, data, nil)
mapResult[interest] = stateOrderList.data.Volume mapResult[interest] = stateOrderList.data.Volume
@ -211,22 +211,22 @@ func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*
return result, nil return result, nil
} }
func (self *itemListState) DumpItemList(db Database) DumpOrderList { func (il *itemListState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} mapResult := DumpOrderList{Volume: il.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil)) orderListIt := trie.NewIterator(il.getTrie(db).NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key) keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) { if common.EmptyHash(keyHash) {
continue continue
} }
if _, exist := self.cachedStorage[keyHash]; exist { if _, exist := il.cachedStorage[keyHash]; exist {
continue continue
} else { } else {
_, content, _, _ := rlp.Split(orderListIt.Value) _, content, _, _ := rlp.Split(orderListIt.Value)
mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content) mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content)
} }
} }
for key, value := range self.cachedStorage { for key, value := range il.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes()) mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
} }
@ -238,44 +238,44 @@ func (self *itemListState) DumpItemList(db Database) DumpOrderList {
sort.Slice(listIds, func(i, j int) bool { sort.Slice(listIds, func(i, j int) bool {
return listIds[i].Cmp(listIds[j]) < 0 return listIds[i].Cmp(listIds[j]) < 0
}) })
result := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} result := DumpOrderList{Volume: il.Volume(), Orders: map[*big.Int]*big.Int{}}
for _, id := range listIds { for _, id := range listIds {
result.Orders[id] = mapResult.Orders[id] result.Orders[id] = mapResult.Orders[id]
} }
return result return result
} }
func (self *LendingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) { func (ls *LendingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
result := &DumpOrderBookInfo{} result := &DumpOrderBookInfo{}
result.Nonce = exhangeObject.data.Nonce result.Nonce = exhangeObject.data.Nonce
result.TradeNonce = exhangeObject.data.TradeNonce result.TradeNonce = exhangeObject.data.TradeNonce
result.BestInvesting = new(big.Int).SetBytes(exhangeObject.getBestInvestingInterest(self.db).Bytes()) result.BestInvesting = new(big.Int).SetBytes(exhangeObject.getBestInvestingInterest(ls.db).Bytes())
result.BestBorrowing = new(big.Int).SetBytes(exhangeObject.getBestBorrowingInterest(self.db).Bytes()) result.BestBorrowing = new(big.Int).SetBytes(exhangeObject.getBestBorrowingInterest(ls.db).Bytes())
lowestLiquidationTime, _ := exhangeObject.getLowestLiquidationTime(self.db) lowestLiquidationTime, _ := exhangeObject.getLowestLiquidationTime(ls.db)
result.LowestLiquidationTime = new(big.Int).SetBytes(lowestLiquidationTime.Bytes()) result.LowestLiquidationTime = new(big.Int).SetBytes(lowestLiquidationTime.Bytes())
return result, nil return result, nil
} }
func (self *liquidationTimeState) DumpItemList(db Database) DumpOrderList { func (lts *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} mapResult := DumpOrderList{Volume: lts.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil)) orderListIt := trie.NewIterator(lts.getTrie(db).NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key) keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) { if common.EmptyHash(keyHash) {
continue continue
} }
if _, exist := self.cachedStorage[keyHash]; exist { if _, exist := lts.cachedStorage[keyHash]; exist {
continue continue
} else { } else {
_, content, _, _ := rlp.Split(orderListIt.Value) _, content, _, _ := rlp.Split(orderListIt.Value)
mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content) mapResult.Orders[new(big.Int).SetBytes(keyHash.Bytes())] = new(big.Int).SetBytes(content)
} }
} }
for key, value := range self.cachedStorage { for key, value := range lts.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes()) mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
} }
@ -287,19 +287,20 @@ func (self *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
sort.Slice(listIds, func(i, j int) bool { sort.Slice(listIds, func(i, j int) bool {
return listIds[i].Cmp(listIds[j]) < 0 return listIds[i].Cmp(listIds[j]) < 0
}) })
result := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}} result := DumpOrderList{Volume: lts.Volume(), Orders: map[*big.Int]*big.Int{}}
for _, id := range listIds { for _, id := range listIds {
result.Orders[id] = mapResult.Orders[id] result.Orders[id] = mapResult.Orders[id]
} }
return mapResult return mapResult
} }
func (self *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getLendingExchange(orderBook) func (ls *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]DumpOrderList{} mapResult := map[*big.Int]DumpOrderList{}
it := trie.NewIterator(exhangeObject.getLiquidationTimeTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getLiquidationTimeTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
unixTimeHash := common.BytesToHash(it.Key) unixTimeHash := common.BytesToHash(it.Key)
if common.EmptyHash(unixTimeHash) { if common.EmptyHash(unixTimeHash) {
@ -311,15 +312,15 @@ func (self *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[
} else { } else {
var data itemList var data itemList
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,unixTime :%v ", orderBook.Hex(), unixTime) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , unixTime : %v", orderBook.Hex(), unixTime)
} }
stateOrderList := newLiquidationTimeState(orderBook, unixTimeHash, data, nil) stateOrderList := newLiquidationTimeState(orderBook, unixTimeHash, data, nil)
mapResult[unixTime] = stateOrderList.DumpItemList(self.db) mapResult[unixTime] = stateOrderList.DumpItemList(ls.db)
} }
} }
for unixTimeHash, itemList := range exhangeObject.liquidationTimeStates { for unixTimeHash, itemList := range exhangeObject.liquidationTimeStates {
if itemList.Volume().Sign() > 0 { if itemList.Volume().Sign() > 0 {
mapResult[new(big.Int).SetBytes(unixTimeHash.Bytes())] = itemList.DumpItemList(self.db) mapResult[new(big.Int).SetBytes(unixTimeHash.Bytes())] = itemList.DumpItemList(ls.db)
} }
} }
listUnixTime := []*big.Int{} listUnixTime := []*big.Int{}
@ -336,13 +337,13 @@ func (self *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[
return result, nil return result, nil
} }
func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*big.Int]LendingItem, error) { func (ls *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*big.Int]LendingItem, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]LendingItem{} mapResult := map[*big.Int]LendingItem{}
it := trie.NewIterator(exhangeObject.getLendingItemTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getLendingItemTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
orderIdHash := common.BytesToHash(it.Key) orderIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(orderIdHash) { if common.EmptyHash(orderIdHash) {
@ -354,7 +355,7 @@ func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*bi
} else { } else {
var data LendingItem var data LendingItem
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,orderId :%v ", orderBook.Hex(), orderId) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , orderId : %v", orderBook.Hex(), orderId)
} }
mapResult[orderId] = data mapResult[orderId] = data
} }
@ -376,13 +377,13 @@ func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*bi
return result, nil return result, nil
} }
func (self *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*big.Int]LendingTrade, error) { func (ls *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*big.Int]LendingTrade, error) {
exhangeObject := self.getLendingExchange(orderBook) exhangeObject := ls.getLendingExchange(orderBook)
if exhangeObject == nil { if exhangeObject == nil {
return nil, fmt.Errorf("Order book not found orderBook : %v ", orderBook.Hex()) return nil, fmt.Errorf("not found orderBook: %v", orderBook.Hex())
} }
mapResult := map[*big.Int]LendingTrade{} mapResult := map[*big.Int]LendingTrade{}
it := trie.NewIterator(exhangeObject.getLendingTradeTrie(self.db).NodeIterator(nil)) it := trie.NewIterator(exhangeObject.getLendingTradeTrie(ls.db).NodeIterator(nil))
for it.Next() { for it.Next() {
tradeIdHash := common.BytesToHash(it.Key) tradeIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(tradeIdHash) { if common.EmptyHash(tradeIdHash) {
@ -394,7 +395,7 @@ func (self *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*bi
} else { } else {
var data LendingTrade var data LendingTrade
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
return nil, fmt.Errorf("Fail when decode order iist orderBook : %v ,tradeId :%v ", orderBook.Hex(), tradeId) return nil, fmt.Errorf("fail when decode order iist orderBook: %v , tradeId : %v", orderBook.Hex(), tradeId)
} }
mapResult[tradeId] = data mapResult[tradeId] = data
} }

View file

@ -10,8 +10,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/globalsign/mgo/bson" "github.com/globalsign/mgo/bson"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -207,7 +207,7 @@ func (l *LendingItem) VerifyLendingItem(state *state.StateDB) error {
if err := l.VerifyLendingStatus(); err != nil { if err := l.VerifyLendingStatus(); err != nil {
return err return err
} }
if valid, _ := IsValidPair(state, l.Relayer, l.LendingToken, l.Term); valid == false { if valid, _ := IsValidPair(state, l.Relayer, l.LendingToken, l.Term); !valid {
return fmt.Errorf("invalid pair . LendToken %s . Term: %v", l.LendingToken.Hex(), l.Term) return fmt.Errorf("invalid pair . LendToken %s . Term: %v", l.LendingToken.Hex(), l.Term)
} }
if l.Status == LendingStatusNew { if l.Status == LendingStatusNew {
@ -308,7 +308,7 @@ func (l *LendingItem) VerifyLendingStatus() error {
} }
func (l *LendingItem) ComputeHash() common.Hash { func (l *LendingItem) ComputeHash() common.Hash {
sha := sha3.NewKeccak256() sha := sha3.NewLegacyKeccak256()
if l.Status == LendingStatusNew { if l.Status == LendingStatusNew {
sha.Write(l.Relayer.Bytes()) sha.Write(l.Relayer.Bytes())
sha.Write(l.UserAddress.Bytes()) sha.Write(l.UserAddress.Bytes())
@ -411,7 +411,7 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
if lendTokenXDCPrice != nil && lendTokenXDCPrice.Sign() > 0 { if lendTokenXDCPrice != nil && lendTokenXDCPrice.Sign() > 0 {
defaultFee := new(big.Int).Mul(quantity, new(big.Int).SetUint64(DefaultFeeRate)) defaultFee := new(big.Int).Mul(quantity, new(big.Int).SetUint64(DefaultFeeRate))
defaultFee = new(big.Int).Div(defaultFee, common.XDCXBaseFee) defaultFee = new(big.Int).Div(defaultFee, common.XDCXBaseFee)
defaultFeeInXDC := common.Big0 var defaultFeeInXDC *big.Int
if lendingToken != common.XDCNativeAddressBinary { if lendingToken != common.XDCNativeAddressBinary {
defaultFeeInXDC = new(big.Int).Mul(defaultFee, lendTokenXDCPrice) defaultFeeInXDC = new(big.Int).Mul(defaultFee, lendTokenXDCPrice)
defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, lendingTokenDecimal) defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, lendingTokenDecimal)
@ -429,8 +429,7 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
// make sure actualBalance >= cancel fee // make sure actualBalance >= cancel fee
lendingBook := GetLendingOrderBookHash(lendingToken, term) lendingBook := GetLendingOrderBookHash(lendingToken, term)
item := lendingStateDb.GetLendingOrder(lendingBook, common.BigToHash(new(big.Int).SetUint64(lendingId))) item := lendingStateDb.GetLendingOrder(lendingBook, common.BigToHash(new(big.Int).SetUint64(lendingId)))
cancelFee := big.NewInt(0) cancelFee := new(big.Int).Mul(item.Quantity, borrowingFeeRate)
cancelFee = new(big.Int).Mul(item.Quantity, borrowingFeeRate)
cancelFee = new(big.Int).Div(cancelFee, common.XDCXBaseCancelFee) cancelFee = new(big.Int).Div(cancelFee, common.XDCXBaseCancelFee)
actualBalance := GetTokenBalance(userAddress, lendingToken, statedb) actualBalance := GetTokenBalance(userAddress, lendingToken, statedb)
@ -459,9 +458,8 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
case LendingStatusCancelled: case LendingStatusCancelled:
lendingBook := GetLendingOrderBookHash(lendingToken, term) lendingBook := GetLendingOrderBookHash(lendingToken, term)
item := lendingStateDb.GetLendingOrder(lendingBook, common.BigToHash(new(big.Int).SetUint64(lendingId))) item := lendingStateDb.GetLendingOrder(lendingBook, common.BigToHash(new(big.Int).SetUint64(lendingId)))
cancelFee := big.NewInt(0)
// Fee == quantityToLend/base lend token decimal *price*borrowFee/LendingCancelFee // Fee == quantityToLend/base lend token decimal *price*borrowFee/LendingCancelFee
cancelFee = new(big.Int).Div(item.Quantity, collateralPrice) cancelFee := new(big.Int).Div(item.Quantity, collateralPrice)
cancelFee = new(big.Int).Mul(cancelFee, borrowingFeeRate) cancelFee = new(big.Int).Mul(cancelFee, borrowingFeeRate)
cancelFee = new(big.Int).Div(cancelFee, common.XDCXBaseCancelFee) cancelFee = new(big.Int).Div(cancelFee, common.XDCXBaseCancelFee)
actualBalance := GetTokenBalance(userAddress, collateralToken, statedb) actualBalance := GetTokenBalance(userAddress, collateralToken, statedb)

View file

@ -12,8 +12,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
"golang.org/x/crypto/sha3"
) )
func TestLendingItem_VerifyLendingSide(t *testing.T) { func TestLendingItem_VerifyLendingSide(t *testing.T) {
@ -515,11 +515,11 @@ func Test_CreateOrder(t *testing.T) {
func sendOrder(nonce uint64) { func sendOrder(nonce uint64) {
rpcClient, err := rpc.DialHTTP("http://localhost:8501") rpcClient, err := rpc.DialHTTP("http://localhost:8501")
defer rpcClient.Close()
if err != nil { if err != nil {
fmt.Println("rpc.DialHTTP failed", "err", err) fmt.Println("rpc.DialHTTP failed", "err", err)
os.Exit(1) os.Exit(1)
} }
defer rpcClient.Close()
rand.Seed(time.Now().UTC().UnixNano()) rand.Seed(time.Now().UTC().UnixNano())
item := &LendingOrderMsg{ item := &LendingOrderMsg{
AccountNonce: nonce, AccountNonce: nonce,
@ -568,9 +568,8 @@ func sendOrder(nonce uint64) {
} }
func computeHash(l *LendingOrderMsg) common.Hash { func computeHash(l *LendingOrderMsg) common.Hash {
sha := sha3.NewKeccak256() sha := sha3.NewLegacyKeccak256()
if l.Status == LendingStatusCancelled { if l.Status == LendingStatusCancelled {
sha := sha3.NewKeccak256()
sha.Write(l.Hash.Bytes()) sha.Write(l.Hash.Bytes())
sha.Write(common.BigToHash(big.NewInt(int64(l.AccountNonce))).Bytes()) sha.Write(common.BigToHash(big.NewInt(int64(l.AccountNonce))).Bytes())
sha.Write(l.UserAddress.Bytes()) sha.Write(l.UserAddress.Bytes())
@ -593,5 +592,4 @@ func computeHash(l *LendingOrderMsg) common.Hash {
sha.Write(common.BigToHash(big.NewInt(int64(l.AccountNonce))).Bytes()) sha.Write(common.BigToHash(big.NewInt(int64(l.AccountNonce))).Bytes())
} }
return common.BytesToHash(sha.Sum(nil)) return common.BytesToHash(sha.Sum(nil))
} }

View file

@ -41,10 +41,7 @@ func IsResignedRelayer(relayer common.Address, statedb *state.StateDB) bool {
slot := RelayerMappingSlot["RESIGN_REQUESTS"] slot := RelayerMappingSlot["RESIGN_REQUESTS"]
locBig := GetLocMappingAtKey(relayer.Hash(), slot) locBig := GetLocMappingAtKey(relayer.Hash(), slot)
locHash := common.BigToHash(locBig) locHash := common.BigToHash(locBig)
if statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), locHash) != (common.Hash{}) { return statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), locHash) != (common.Hash{})
return true
}
return false
} }
func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 { func GetBaseTokenLength(relayer common.Address, statedb *state.StateDB) uint64 {
@ -235,7 +232,7 @@ func CheckAddTokenBalance(addr common.Address, value *big.Int, token common.Addr
newBalance := new(big.Int).Add(balance, value) newBalance := new(big.Int).Add(balance, value)
log.Debug("CheckAddTokenBalance settle balance: ADD TOKEN BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance) log.Debug("CheckAddTokenBalance settle balance: ADD TOKEN BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
if common.BigToHash(newBalance).Big().Cmp(newBalance) != 0 { if common.BigToHash(newBalance).Big().Cmp(newBalance) != 0 {
return nil, fmt.Errorf("Overflow when try add token balance , max is 2^256 , balance : %v , value:%v ", balance, value) return nil, fmt.Errorf("overflow when try add token balance , max is 2^256 , balance : %v , value : %v", balance, value)
} else { } else {
return newBalance, nil return newBalance, nil
} }

View file

@ -19,10 +19,11 @@ package lendingstate
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
"io" "io"
"math/big" "math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
) )
type itemListState struct { type itemListState struct {
@ -46,8 +47,8 @@ type itemListState struct {
onDirty func(price common.Hash) // Callback method to mark a state object newly dirty onDirty func(price common.Hash) // Callback method to mark a state object newly dirty
} }
func (s *itemListState) empty() bool { func (il *itemListState) empty() bool {
return s.data.Volume == nil || s.data.Volume.Sign() == 0 return il.data.Volume == nil || il.data.Volume.Sign() == 0
} }
func newItemListState(lendingBook common.Hash, key common.Hash, data itemList, onDirty func(price common.Hash)) *itemListState { func newItemListState(lendingBook common.Hash, key common.Hash, data itemList, onDirty func(price common.Hash)) *itemListState {
@ -62,132 +63,132 @@ func newItemListState(lendingBook common.Hash, key common.Hash, data itemList, o
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *itemListState) EncodeRLP(w io.Writer) error { func (il *itemListState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, il.data)
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *itemListState) setError(err error) { func (il *itemListState) setError(err error) {
if self.dbErr == nil { if il.dbErr == nil {
self.dbErr = err il.dbErr = err
} }
} }
func (c *itemListState) getTrie(db Database) Trie { func (il *itemListState) getTrie(db Database) Trie {
if c.trie == nil { if il.trie == nil {
var err error var err error
c.trie, err = db.OpenStorageTrie(c.key, c.data.Root) il.trie, err = db.OpenStorageTrie(il.key, il.data.Root)
if err != nil { if err != nil {
c.trie, _ = db.OpenStorageTrie(c.key, EmptyHash) il.trie, _ = db.OpenStorageTrie(il.key, EmptyHash)
c.setError(fmt.Errorf("can't create storage trie: %v", err)) il.setError(fmt.Errorf("can't create storage trie: %v", err))
} }
} }
return c.trie return il.trie
} }
func (self *itemListState) GetOrderAmount(db Database, orderId common.Hash) common.Hash { func (il *itemListState) GetOrderAmount(db Database, orderId common.Hash) common.Hash {
amount, exists := self.cachedStorage[orderId] amount, exists := il.cachedStorage[orderId]
if exists { if exists {
return amount return amount
} }
// Load from DB in case it is missing. // Load from DB in case it is missing.
enc, err := self.getTrie(db).TryGet(orderId[:]) enc, err := il.getTrie(db).TryGet(orderId[:])
if err != nil { if err != nil {
self.setError(err) il.setError(err)
return EmptyHash return EmptyHash
} }
if len(enc) > 0 { if len(enc) > 0 {
_, content, _, err := rlp.Split(enc) _, content, _, err := rlp.Split(enc)
if err != nil { if err != nil {
self.setError(err) il.setError(err)
} }
amount.SetBytes(content) amount.SetBytes(content)
} }
if (amount != common.Hash{}) { if (amount != common.Hash{}) {
self.cachedStorage[orderId] = amount il.cachedStorage[orderId] = amount
} }
return amount return amount
} }
func (self *itemListState) insertLendingItem(db Database, orderId common.Hash, amount common.Hash) { func (il *itemListState) insertLendingItem(db Database, orderId common.Hash, amount common.Hash) {
self.setOrderItem(orderId, amount) il.setOrderItem(orderId, amount)
self.setError(self.getTrie(db).TryUpdate(orderId[:], amount[:])) il.setError(il.getTrie(db).TryUpdate(orderId[:], amount[:]))
} }
func (self *itemListState) removeOrderItem(db Database, orderId common.Hash) { func (il *itemListState) removeOrderItem(db Database, orderId common.Hash) {
tr := self.getTrie(db) tr := il.getTrie(db)
self.setError(tr.TryDelete(orderId[:])) il.setError(tr.TryDelete(orderId[:]))
self.setOrderItem(orderId, EmptyHash) il.setOrderItem(orderId, EmptyHash)
} }
func (self *itemListState) setOrderItem(orderId common.Hash, amount common.Hash) { func (il *itemListState) setOrderItem(orderId common.Hash, amount common.Hash) {
self.cachedStorage[orderId] = amount il.cachedStorage[orderId] = amount
self.dirtyStorage[orderId] = amount il.dirtyStorage[orderId] = amount
if self.onDirty != nil { if il.onDirty != nil {
self.onDirty(self.key) il.onDirty(il.key)
self.onDirty = nil il.onDirty = nil
} }
} }
// updateAskTrie writes cached storage modifications into the object's storage trie. // updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *itemListState) updateTrie(db Database) Trie { func (il *itemListState) updateTrie(db Database) Trie {
tr := self.getTrie(db) tr := il.getTrie(db)
for orderId, amount := range self.dirtyStorage { for orderId, amount := range il.dirtyStorage {
delete(self.dirtyStorage, orderId) delete(il.dirtyStorage, orderId)
if amount == EmptyHash { if amount == EmptyHash {
self.setError(tr.TryDelete(orderId[:])) il.setError(tr.TryDelete(orderId[:]))
continue continue
} }
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(amount[:], "\x00")) v, _ := rlp.EncodeToBytes(bytes.TrimLeft(amount[:], "\x00"))
self.setError(tr.TryUpdate(orderId[:], v)) il.setError(tr.TryUpdate(orderId[:], v))
} }
return tr return tr
} }
// UpdateRoot sets the trie root to the current root tradeId of // UpdateRoot sets the trie root to the current root tradeId of
func (self *itemListState) updateRoot(db Database) error { func (il *itemListState) updateRoot(db Database) error {
self.updateTrie(db) il.updateTrie(db)
if self.dbErr != nil { if il.dbErr != nil {
return self.dbErr return il.dbErr
} }
root, err := self.trie.Commit(nil) root, err := il.trie.Commit(nil)
if err == nil { if err == nil {
self.data.Root = root il.data.Root = root
} }
return err return err
} }
func (self *itemListState) deepCopy(db *LendingStateDB, onDirty func(price common.Hash)) *itemListState { func (il *itemListState) deepCopy(db *LendingStateDB, onDirty func(price common.Hash)) *itemListState {
stateOrderList := newItemListState(self.lendingBook, self.key, self.data, onDirty) stateOrderList := newItemListState(il.lendingBook, il.key, il.data, onDirty)
if self.trie != nil { if il.trie != nil {
stateOrderList.trie = db.db.CopyTrie(self.trie) stateOrderList.trie = db.db.CopyTrie(il.trie)
} }
for orderId, amount := range self.dirtyStorage { for orderId, amount := range il.dirtyStorage {
stateOrderList.dirtyStorage[orderId] = amount stateOrderList.dirtyStorage[orderId] = amount
} }
for orderId, amount := range self.cachedStorage { for orderId, amount := range il.cachedStorage {
stateOrderList.cachedStorage[orderId] = amount stateOrderList.cachedStorage[orderId] = amount
} }
return stateOrderList return stateOrderList
} }
func (c *itemListState) AddVolume(amount *big.Int) { func (il *itemListState) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount)) il.setVolume(new(big.Int).Add(il.data.Volume, amount))
} }
func (c *itemListState) subVolume(amount *big.Int) { func (il *itemListState) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount)) il.setVolume(new(big.Int).Sub(il.data.Volume, amount))
} }
func (self *itemListState) setVolume(volume *big.Int) { func (il *itemListState) setVolume(volume *big.Int) {
self.data.Volume = volume il.data.Volume = volume
if self.onDirty != nil { if il.onDirty != nil {
self.onDirty(self.key) il.onDirty(il.key)
self.onDirty = nil il.onDirty = nil
} }
} }
func (self *itemListState) Volume() *big.Int { func (il *itemListState) Volume() *big.Int {
return self.data.Volume return il.data.Volume
} }

View file

@ -108,14 +108,14 @@ func newStateExchanges(db *LendingStateDB, hash common.Hash, data lendingObject,
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (self *lendingExchangeState) EncodeRLP(w io.Writer) error { func (le *lendingExchangeState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, self.data) return rlp.Encode(w, le.data)
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *lendingExchangeState) setError(err error) { func (le *lendingExchangeState) setError(err error) {
if self.dbErr == nil { if le.dbErr == nil {
self.dbErr = err le.dbErr = err
} }
} }
@ -123,63 +123,64 @@ func (self *lendingExchangeState) setError(err error) {
Get Trie Get Trie
*/ */
func (self *lendingExchangeState) getLendingItemTrie(db Database) Trie { func (le *lendingExchangeState) getLendingItemTrie(db Database) Trie {
if self.lendingItemTrie == nil { if le.lendingItemTrie == nil {
var err error var err error
self.lendingItemTrie, err = db.OpenStorageTrie(self.lendingBook, self.data.LendingItemRoot) le.lendingItemTrie, err = db.OpenStorageTrie(le.lendingBook, le.data.LendingItemRoot)
if err != nil { if err != nil {
self.lendingItemTrie, _ = db.OpenStorageTrie(self.lendingBook, EmptyHash) le.lendingItemTrie, _ = db.OpenStorageTrie(le.lendingBook, EmptyHash)
self.setError(fmt.Errorf("can't create Lendings trie: %v", err)) le.setError(fmt.Errorf("can't create Lendings trie: %v", err))
} }
} }
return self.lendingItemTrie return le.lendingItemTrie
} }
func (self *lendingExchangeState) getLendingTradeTrie(db Database) Trie { func (le *lendingExchangeState) getLendingTradeTrie(db Database) Trie {
if self.lendingTradeTrie == nil { if le.lendingTradeTrie == nil {
var err error var err error
self.lendingTradeTrie, err = db.OpenStorageTrie(self.lendingBook, self.data.LendingTradeRoot) le.lendingTradeTrie, err = db.OpenStorageTrie(le.lendingBook, le.data.LendingTradeRoot)
if err != nil { if err != nil {
self.lendingTradeTrie, _ = db.OpenStorageTrie(self.lendingBook, EmptyHash) le.lendingTradeTrie, _ = db.OpenStorageTrie(le.lendingBook, EmptyHash)
self.setError(fmt.Errorf("can't create Lendings trie: %v", err)) le.setError(fmt.Errorf("can't create Lendings trie: %v", err))
} }
} }
return self.lendingTradeTrie return le.lendingTradeTrie
}
func (self *lendingExchangeState) getInvestingTrie(db Database) Trie {
if self.investingTrie == nil {
var err error
self.investingTrie, err = db.OpenStorageTrie(self.lendingBook, self.data.InvestingRoot)
if err != nil {
self.investingTrie, _ = db.OpenStorageTrie(self.lendingBook, EmptyHash)
self.setError(fmt.Errorf("can't create Lendings trie: %v", err))
}
}
return self.investingTrie
} }
func (self *lendingExchangeState) getBorrowingTrie(db Database) Trie { func (le *lendingExchangeState) getInvestingTrie(db Database) Trie {
if self.borrowingTrie == nil { if le.investingTrie == nil {
var err error var err error
self.borrowingTrie, err = db.OpenStorageTrie(self.lendingBook, self.data.BorrowingRoot) le.investingTrie, err = db.OpenStorageTrie(le.lendingBook, le.data.InvestingRoot)
if err != nil { if err != nil {
self.borrowingTrie, _ = db.OpenStorageTrie(self.lendingBook, EmptyHash) le.investingTrie, _ = db.OpenStorageTrie(le.lendingBook, EmptyHash)
self.setError(fmt.Errorf("can't create bids trie: %v", err)) le.setError(fmt.Errorf("can't create Lendings trie: %v", err))
} }
} }
return self.borrowingTrie return le.investingTrie
} }
func (self *lendingExchangeState) getLiquidationTimeTrie(db Database) Trie { func (le *lendingExchangeState) getBorrowingTrie(db Database) Trie {
if self.liquidationTimeTrie == nil { if le.borrowingTrie == nil {
var err error var err error
self.liquidationTimeTrie, err = db.OpenStorageTrie(self.lendingBook, self.data.LiquidationTimeRoot) le.borrowingTrie, err = db.OpenStorageTrie(le.lendingBook, le.data.BorrowingRoot)
if err != nil { if err != nil {
self.liquidationTimeTrie, _ = db.OpenStorageTrie(self.lendingBook, EmptyHash) le.borrowingTrie, _ = db.OpenStorageTrie(le.lendingBook, EmptyHash)
self.setError(fmt.Errorf("can't create bids trie: %v", err)) le.setError(fmt.Errorf("can't create bids trie: %v", err))
} }
} }
return self.liquidationTimeTrie return le.borrowingTrie
}
func (le *lendingExchangeState) getLiquidationTimeTrie(db Database) Trie {
if le.liquidationTimeTrie == nil {
var err error
le.liquidationTimeTrie, err = db.OpenStorageTrie(le.lendingBook, le.data.LiquidationTimeRoot)
if err != nil {
le.liquidationTimeTrie, _ = db.OpenStorageTrie(le.lendingBook, EmptyHash)
le.setError(fmt.Errorf("can't create bids trie: %v", err))
}
}
return le.liquidationTimeTrie
} }
/* /*
@ -187,16 +188,16 @@ func (self *lendingExchangeState) getLiquidationTimeTrie(db Database) Trie {
Get State Get State
*/ */
func (self *lendingExchangeState) getBorrowingOrderList(db Database, rate common.Hash) (stateOrderList *itemListState) { func (le *lendingExchangeState) getBorrowingOrderList(db Database, rate common.Hash) (stateOrderList *itemListState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.borrowingStates[rate]; obj != nil { if obj := le.borrowingStates[rate]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getBorrowingTrie(db).TryGet(rate[:]) enc, err := le.getBorrowingTrie(db).TryGet(rate[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) le.setError(err)
return nil return nil
} }
var data itemList var data itemList
@ -205,21 +206,21 @@ func (self *lendingExchangeState) getBorrowingOrderList(db Database, rate common
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newItemListState(self.lendingBook, rate, data, self.MarkBorrowingDirty) obj := newItemListState(le.lendingBook, rate, data, le.MarkBorrowingDirty)
self.borrowingStates[rate] = obj le.borrowingStates[rate] = obj
return obj return obj
} }
func (self *lendingExchangeState) getInvestingOrderList(db Database, rate common.Hash) (stateOrderList *itemListState) { func (le *lendingExchangeState) getInvestingOrderList(db Database, rate common.Hash) (stateOrderList *itemListState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.investingStates[rate]; obj != nil { if obj := le.investingStates[rate]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getInvestingTrie(db).TryGet(rate[:]) enc, err := le.getInvestingTrie(db).TryGet(rate[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) le.setError(err)
return nil return nil
} }
var data itemList var data itemList
@ -228,21 +229,21 @@ func (self *lendingExchangeState) getInvestingOrderList(db Database, rate common
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newItemListState(self.lendingBook, rate, data, self.MarkInvestingDirty) obj := newItemListState(le.lendingBook, rate, data, le.MarkInvestingDirty)
self.investingStates[rate] = obj le.investingStates[rate] = obj
return obj return obj
} }
func (self *lendingExchangeState) getLiquidationTimeOrderList(db Database, time common.Hash) (stateObject *liquidationTimeState) { func (le *lendingExchangeState) getLiquidationTimeOrderList(db Database, time common.Hash) (stateObject *liquidationTimeState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.liquidationTimeStates[time]; obj != nil { if obj := le.liquidationTimeStates[time]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getLiquidationTimeTrie(db).TryGet(time[:]) enc, err := le.getLiquidationTimeTrie(db).TryGet(time[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) le.setError(err)
return nil return nil
} }
var data itemList var data itemList
@ -251,21 +252,21 @@ func (self *lendingExchangeState) getLiquidationTimeOrderList(db Database, time
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newLiquidationTimeState(self.lendingBook, time, data, self.MarkLiquidationTimeDirty) obj := newLiquidationTimeState(le.lendingBook, time, data, le.MarkLiquidationTimeDirty)
self.liquidationTimeStates[time] = obj le.liquidationTimeStates[time] = obj
return obj return obj
} }
func (self *lendingExchangeState) getLendingItem(db Database, lendingId common.Hash) (stateObject *lendingItemState) { func (le *lendingExchangeState) getLendingItem(db Database, lendingId common.Hash) (stateObject *lendingItemState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.lendingItemStates[lendingId]; obj != nil { if obj := le.lendingItemStates[lendingId]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getLendingItemTrie(db).TryGet(lendingId[:]) enc, err := le.getLendingItemTrie(db).TryGet(lendingId[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) le.setError(err)
return nil return nil
} }
var data LendingItem var data LendingItem
@ -274,21 +275,21 @@ func (self *lendingExchangeState) getLendingItem(db Database, lendingId common.H
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newLendinItemState(self.lendingBook, lendingId, data, self.MarkLendingItemDirty) obj := newLendinItemState(le.lendingBook, lendingId, data, le.MarkLendingItemDirty)
self.lendingItemStates[lendingId] = obj le.lendingItemStates[lendingId] = obj
return obj return obj
} }
func (self *lendingExchangeState) getLendingTrade(db Database, tradeId common.Hash) (stateObject *lendingTradeState) { func (le *lendingExchangeState) getLendingTrade(db Database, tradeId common.Hash) (stateObject *lendingTradeState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.lendingTradeStates[tradeId]; obj != nil { if obj := le.lendingTradeStates[tradeId]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.getLendingTradeTrie(db).TryGet(tradeId[:]) enc, err := le.getLendingTradeTrie(db).TryGet(tradeId[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) le.setError(err)
return nil return nil
} }
var data LendingTrade var data LendingTrade
@ -297,8 +298,8 @@ func (self *lendingExchangeState) getLendingTrade(db Database, tradeId common.Ha
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newLendingTradeState(self.lendingBook, tradeId, data, self.MarkLendingTradeDirty) obj := newLendingTradeState(le.lendingBook, tradeId, data, le.MarkLendingTradeDirty)
self.lendingTradeStates[tradeId] = obj le.lendingTradeStates[tradeId] = obj
return obj return obj
} }
@ -307,46 +308,47 @@ func (self *lendingExchangeState) getLendingTrade(db Database, tradeId common.Ha
Update Trie Update Trie
*/ */
func (self *lendingExchangeState) updateLendingTimeTrie(db Database) Trie { func (le *lendingExchangeState) updateLendingTimeTrie(db Database) Trie {
tr := self.getLendingItemTrie(db) tr := le.getLendingItemTrie(db)
for lendingId, lendingItem := range self.lendingItemStates { for lendingId, lendingItem := range le.lendingItemStates {
if _, isDirty := self.lendingItemStatesDirty[lendingId]; isDirty { if _, isDirty := le.lendingItemStatesDirty[lendingId]; isDirty {
delete(self.lendingItemStatesDirty, lendingId) delete(le.lendingItemStatesDirty, lendingId)
if lendingItem.empty() { if lendingItem.empty() {
self.setError(tr.TryDelete(lendingId[:])) le.setError(tr.TryDelete(lendingId[:]))
continue continue
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(lendingItem) v, _ := rlp.EncodeToBytes(lendingItem)
self.setError(tr.TryUpdate(lendingId[:], v)) le.setError(tr.TryUpdate(lendingId[:], v))
} }
} }
return tr return tr
} }
func (self *lendingExchangeState) updateLendingTradeTrie(db Database) Trie { func (le *lendingExchangeState) updateLendingTradeTrie(db Database) Trie {
tr := self.getLendingTradeTrie(db) tr := le.getLendingTradeTrie(db)
for tradeId, lendingTradeItem := range self.lendingTradeStates { for tradeId, lendingTradeItem := range le.lendingTradeStates {
if _, isDirty := self.lendingTradeStatesDirty[tradeId]; isDirty { if _, isDirty := le.lendingTradeStatesDirty[tradeId]; isDirty {
delete(self.lendingTradeStatesDirty, tradeId) delete(le.lendingTradeStatesDirty, tradeId)
if lendingTradeItem.empty() { if lendingTradeItem.empty() {
self.setError(tr.TryDelete(tradeId[:])) le.setError(tr.TryDelete(tradeId[:]))
continue continue
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(lendingTradeItem) v, _ := rlp.EncodeToBytes(lendingTradeItem)
self.setError(tr.TryUpdate(tradeId[:], v)) le.setError(tr.TryUpdate(tradeId[:], v))
} }
} }
return tr return tr
} }
func (self *lendingExchangeState) updateBorrowingTrie(db Database) Trie {
tr := self.getBorrowingTrie(db) func (le *lendingExchangeState) updateBorrowingTrie(db Database) Trie {
for rate, orderList := range self.borrowingStates { tr := le.getBorrowingTrie(db)
if _, isDirty := self.borrowingStatesDirty[rate]; isDirty { for rate, orderList := range le.borrowingStates {
delete(self.borrowingStatesDirty, rate) if _, isDirty := le.borrowingStatesDirty[rate]; isDirty {
delete(le.borrowingStatesDirty, rate)
if orderList.empty() { if orderList.empty() {
self.setError(tr.TryDelete(rate[:])) le.setError(tr.TryDelete(rate[:]))
continue continue
} }
err := orderList.updateRoot(db) err := orderList.updateRoot(db)
@ -355,19 +357,19 @@ func (self *lendingExchangeState) updateBorrowingTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderList) v, _ := rlp.EncodeToBytes(orderList)
self.setError(tr.TryUpdate(rate[:], v)) le.setError(tr.TryUpdate(rate[:], v))
} }
} }
return tr return tr
} }
func (self *lendingExchangeState) updateInvestingTrie(db Database) Trie { func (le *lendingExchangeState) updateInvestingTrie(db Database) Trie {
tr := self.getInvestingTrie(db) tr := le.getInvestingTrie(db)
for rate, orderList := range self.investingStates { for rate, orderList := range le.investingStates {
if _, isDirty := self.investingStatesDirty[rate]; isDirty { if _, isDirty := le.investingStatesDirty[rate]; isDirty {
delete(self.investingStatesDirty, rate) delete(le.investingStatesDirty, rate)
if orderList.empty() { if orderList.empty() {
self.setError(tr.TryDelete(rate[:])) le.setError(tr.TryDelete(rate[:]))
continue continue
} }
err := orderList.updateRoot(db) err := orderList.updateRoot(db)
@ -376,19 +378,19 @@ func (self *lendingExchangeState) updateInvestingTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderList) v, _ := rlp.EncodeToBytes(orderList)
self.setError(tr.TryUpdate(rate[:], v)) le.setError(tr.TryUpdate(rate[:], v))
} }
} }
return tr return tr
} }
func (self *lendingExchangeState) updateLiquidationTimeTrie(db Database) Trie { func (le *lendingExchangeState) updateLiquidationTimeTrie(db Database) Trie {
tr := self.getLiquidationTimeTrie(db) tr := le.getLiquidationTimeTrie(db)
for time, itemList := range self.liquidationTimeStates { for time, itemList := range le.liquidationTimeStates {
if _, isDirty := self.liquidationTimestatesDirty[time]; isDirty { if _, isDirty := le.liquidationTimestatesDirty[time]; isDirty {
delete(self.liquidationTimestatesDirty, time) delete(le.liquidationTimestatesDirty, time)
if itemList.empty() { if itemList.empty() {
self.setError(tr.TryDelete(time[:])) le.setError(tr.TryDelete(time[:]))
continue continue
} }
err := itemList.updateRoot(db) err := itemList.updateRoot(db)
@ -397,7 +399,7 @@ func (self *lendingExchangeState) updateLiquidationTimeTrie(db Database) Trie {
} }
// Encoding []byte cannot fail, ok to ignore the error. // Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(itemList) v, _ := rlp.EncodeToBytes(itemList)
self.setError(tr.TryUpdate(time[:], v)) le.setError(tr.TryUpdate(time[:], v))
} }
} }
return tr return tr
@ -407,69 +409,69 @@ func (self *lendingExchangeState) updateLiquidationTimeTrie(db Database) Trie {
Update Root Update Root
*/ */
func (self *lendingExchangeState) updateOrderRoot(db Database) { func (le *lendingExchangeState) updateOrderRoot(db Database) {
self.updateLendingTimeTrie(db) le.updateLendingTimeTrie(db)
self.data.LendingItemRoot = self.lendingItemTrie.Hash() le.data.LendingItemRoot = le.lendingItemTrie.Hash()
} }
func (self *lendingExchangeState) updateInvestingRoot(db Database) error { func (le *lendingExchangeState) updateInvestingRoot(db Database) error {
self.updateInvestingTrie(db) le.updateInvestingTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
self.data.InvestingRoot = self.investingTrie.Hash() le.data.InvestingRoot = le.investingTrie.Hash()
return nil return nil
} }
func (self *lendingExchangeState) updateBorrowingRoot(db Database) { func (le *lendingExchangeState) updateBorrowingRoot(db Database) {
self.updateBorrowingTrie(db) le.updateBorrowingTrie(db)
self.data.BorrowingRoot = self.borrowingTrie.Hash() le.data.BorrowingRoot = le.borrowingTrie.Hash()
} }
func (self *lendingExchangeState) updateLiquidationTimeRoot(db Database) { func (le *lendingExchangeState) updateLiquidationTimeRoot(db Database) {
self.updateLiquidationTimeTrie(db) le.updateLiquidationTimeTrie(db)
self.data.LiquidationTimeRoot = self.liquidationTimeTrie.Hash() le.data.LiquidationTimeRoot = le.liquidationTimeTrie.Hash()
} }
func (self *lendingExchangeState) updateLendingTradeRoot(db Database) { func (le *lendingExchangeState) updateLendingTradeRoot(db Database) {
self.updateLendingTradeTrie(db) le.updateLendingTradeTrie(db)
self.data.LendingTradeRoot = self.lendingTradeTrie.Hash() le.data.LendingTradeRoot = le.lendingTradeTrie.Hash()
} }
/** /**
Commit Trie Commit Trie
*/ */
func (self *lendingExchangeState) CommitLendingItemTrie(db Database) error { func (le *lendingExchangeState) CommitLendingItemTrie(db Database) error {
self.updateLendingTimeTrie(db) le.updateLendingTimeTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
root, err := self.lendingItemTrie.Commit(nil) root, err := le.lendingItemTrie.Commit(nil)
if err == nil { if err == nil {
self.data.LendingItemRoot = root le.data.LendingItemRoot = root
} }
return err return err
} }
func (self *lendingExchangeState) CommitLendingTradeTrie(db Database) error { func (le *lendingExchangeState) CommitLendingTradeTrie(db Database) error {
self.updateLendingTradeTrie(db) le.updateLendingTradeTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
root, err := self.lendingTradeTrie.Commit(nil) root, err := le.lendingTradeTrie.Commit(nil)
if err == nil { if err == nil {
self.data.LendingTradeRoot = root le.data.LendingTradeRoot = root
} }
return err return err
} }
func (self *lendingExchangeState) CommitInvestingTrie(db Database) error { func (le *lendingExchangeState) CommitInvestingTrie(db Database) error {
self.updateInvestingTrie(db) le.updateInvestingTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
root, err := self.investingTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := le.investingTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList itemList var orderList itemList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -480,17 +482,17 @@ func (self *lendingExchangeState) CommitInvestingTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.InvestingRoot = root le.data.InvestingRoot = root
} }
return err return err
} }
func (self *lendingExchangeState) CommitBorrowingTrie(db Database) error { func (le *lendingExchangeState) CommitBorrowingTrie(db Database) error {
self.updateBorrowingTrie(db) le.updateBorrowingTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
root, err := self.borrowingTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := le.borrowingTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList itemList var orderList itemList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -501,17 +503,17 @@ func (self *lendingExchangeState) CommitBorrowingTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.BorrowingRoot = root le.data.BorrowingRoot = root
} }
return err return err
} }
func (self *lendingExchangeState) CommitLiquidationTimeTrie(db Database) error { func (le *lendingExchangeState) CommitLiquidationTimeTrie(db Database) error {
self.updateLiquidationTimeTrie(db) le.updateLiquidationTimeTrie(db)
if self.dbErr != nil { if le.dbErr != nil {
return self.dbErr return le.dbErr
} }
root, err := self.liquidationTimeTrie.Commit(func(leaf []byte, parent common.Hash) error { root, err := le.liquidationTimeTrie.Commit(func(leaf []byte, parent common.Hash) error {
var orderList itemList var orderList itemList
if err := rlp.DecodeBytes(leaf, &orderList); err != nil { if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil return nil
@ -522,7 +524,7 @@ func (self *lendingExchangeState) CommitLiquidationTimeTrie(db Database) error {
return nil return nil
}) })
if err == nil { if err == nil {
self.data.LiquidationTimeRoot = root le.data.LiquidationTimeRoot = root
} }
return err return err
} }
@ -532,11 +534,11 @@ func (self *lendingExchangeState) CommitLiquidationTimeTrie(db Database) error {
Get Trie Data Get Trie Data
*/ */
func (self *lendingExchangeState) getBestInvestingInterest(db Database) common.Hash { func (le *lendingExchangeState) getBestInvestingInterest(db Database) common.Hash {
trie := self.getInvestingTrie(db) trie := le.getInvestingTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue() encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best investing rate", "orderbook", self.lendingBook.Hex()) log.Error("Failed find best investing rate", "orderbook", le.lendingBook.Hex())
return EmptyHash return EmptyHash
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -545,23 +547,23 @@ func (self *lendingExchangeState) getBestInvestingInterest(db Database) common.H
} }
// Insert into the live set. // Insert into the live set.
interest := common.BytesToHash(encKey) interest := common.BytesToHash(encKey)
if _, exist := self.investingStates[interest]; !exist { if _, exist := le.investingStates[interest]; !exist {
var data itemList var data itemList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best investing rate", "err", err) log.Error("Failed to decode state get best investing rate", "err", err)
return EmptyHash return EmptyHash
} }
obj := newItemListState(self.lendingBook, interest, data, self.MarkInvestingDirty) obj := newItemListState(le.lendingBook, interest, data, le.MarkInvestingDirty)
self.investingStates[interest] = obj le.investingStates[interest] = obj
} }
return interest return interest
} }
func (self *lendingExchangeState) getBestBorrowingInterest(db Database) common.Hash { func (le *lendingExchangeState) getBestBorrowingInterest(db Database) common.Hash {
trie := self.getBorrowingTrie(db) trie := le.getBorrowingTrie(db)
encKey, encValue, err := trie.TryGetBestRightKeyAndValue() encKey, encValue, err := trie.TryGetBestRightKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best key bid trie ", "orderbook", self.lendingBook.Hex()) log.Error("Failed find best key bid trie ", "orderbook", le.lendingBook.Hex())
return EmptyHash return EmptyHash
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -570,23 +572,23 @@ func (self *lendingExchangeState) getBestBorrowingInterest(db Database) common.H
} }
// Insert into the live set. // Insert into the live set.
interest := common.BytesToHash(encKey) interest := common.BytesToHash(encKey)
if _, exist := self.borrowingStates[interest]; !exist { if _, exist := le.borrowingStates[interest]; !exist {
var data itemList var data itemList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best bid trie", "err", err) log.Error("Failed to decode state get best bid trie", "err", err)
return EmptyHash return EmptyHash
} }
obj := newItemListState(self.lendingBook, interest, data, self.MarkBorrowingDirty) obj := newItemListState(le.lendingBook, interest, data, le.MarkBorrowingDirty)
self.borrowingStates[interest] = obj le.borrowingStates[interest] = obj
} }
return interest return interest
} }
func (self *lendingExchangeState) getLowestLiquidationTime(db Database) (common.Hash, *liquidationTimeState) { func (le *lendingExchangeState) getLowestLiquidationTime(db Database) (common.Hash, *liquidationTimeState) {
trie := self.getLiquidationTimeTrie(db) trie := le.getLiquidationTimeTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue() encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
log.Error("Failed find best liquidation time trie ", "orderBook", self.lendingBook.Hex()) log.Error("Failed find best liquidation time trie ", "orderBook", le.lendingBook.Hex())
return EmptyHash, nil return EmptyHash, nil
} }
if len(encKey) == 0 || len(encValue) == 0 { if len(encKey) == 0 || len(encValue) == 0 {
@ -594,15 +596,15 @@ func (self *lendingExchangeState) getLowestLiquidationTime(db Database) (common.
return EmptyHash, nil return EmptyHash, nil
} }
price := common.BytesToHash(encKey) price := common.BytesToHash(encKey)
obj, exist := self.liquidationTimeStates[price] obj, exist := le.liquidationTimeStates[price]
if !exist { if !exist {
var data itemList var data itemList
if err := rlp.DecodeBytes(encValue, &data); err != nil { if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get liquidation time trie", "err", err) log.Error("Failed to decode state get liquidation time trie", "err", err)
return EmptyHash, nil return EmptyHash, nil
} }
obj = newLiquidationTimeState(self.lendingBook, price, data, self.MarkLiquidationTimeDirty) obj = newLiquidationTimeState(le.lendingBook, price, data, le.MarkLiquidationTimeDirty)
self.liquidationTimeStates[price] = obj le.liquidationTimeStates[price] = obj
} }
if obj.empty() { if obj.empty() {
return EmptyHash, nil return EmptyHash, nil
@ -610,193 +612,194 @@ func (self *lendingExchangeState) getLowestLiquidationTime(db Database) (common.
return price, obj return price, obj
} }
func (self *lendingExchangeState) deepCopy(db *LendingStateDB, onDirty func(hash common.Hash)) *lendingExchangeState { func (le *lendingExchangeState) deepCopy(db *LendingStateDB, onDirty func(hash common.Hash)) *lendingExchangeState {
stateExchanges := newStateExchanges(db, self.lendingBook, self.data, onDirty) stateExchanges := newStateExchanges(db, le.lendingBook, le.data, onDirty)
if self.investingTrie != nil { if le.investingTrie != nil {
stateExchanges.investingTrie = db.db.CopyTrie(self.investingTrie) stateExchanges.investingTrie = db.db.CopyTrie(le.investingTrie)
} }
if self.borrowingTrie != nil { if le.borrowingTrie != nil {
stateExchanges.borrowingTrie = db.db.CopyTrie(self.borrowingTrie) stateExchanges.borrowingTrie = db.db.CopyTrie(le.borrowingTrie)
} }
if self.lendingItemTrie != nil { if le.lendingItemTrie != nil {
stateExchanges.lendingItemTrie = db.db.CopyTrie(self.lendingItemTrie) stateExchanges.lendingItemTrie = db.db.CopyTrie(le.lendingItemTrie)
} }
for key, value := range self.borrowingStates { for key, value := range le.borrowingStates {
stateExchanges.borrowingStates[key] = value.deepCopy(db, self.MarkBorrowingDirty) stateExchanges.borrowingStates[key] = value.deepCopy(db, le.MarkBorrowingDirty)
} }
for key := range self.borrowingStatesDirty { for key := range le.borrowingStatesDirty {
stateExchanges.borrowingStatesDirty[key] = struct{}{} stateExchanges.borrowingStatesDirty[key] = struct{}{}
} }
for key, value := range self.investingStates { for key, value := range le.investingStates {
stateExchanges.investingStates[key] = value.deepCopy(db, self.MarkInvestingDirty) stateExchanges.investingStates[key] = value.deepCopy(db, le.MarkInvestingDirty)
} }
for key := range self.investingStatesDirty { for key := range le.investingStatesDirty {
stateExchanges.investingStatesDirty[key] = struct{}{} stateExchanges.investingStatesDirty[key] = struct{}{}
} }
for key, value := range self.lendingItemStates { for key, value := range le.lendingItemStates {
stateExchanges.lendingItemStates[key] = value.deepCopy(self.MarkLendingItemDirty) stateExchanges.lendingItemStates[key] = value.deepCopy(le.MarkLendingItemDirty)
} }
for orderId := range self.lendingItemStatesDirty { for orderId := range le.lendingItemStatesDirty {
stateExchanges.lendingItemStatesDirty[orderId] = struct{}{} stateExchanges.lendingItemStatesDirty[orderId] = struct{}{}
} }
for key, value := range self.lendingTradeStates { for key, value := range le.lendingTradeStates {
stateExchanges.lendingTradeStates[key] = value.deepCopy(self.MarkLendingTradeDirty) stateExchanges.lendingTradeStates[key] = value.deepCopy(le.MarkLendingTradeDirty)
} }
for orderId := range self.lendingTradeStatesDirty { for orderId := range le.lendingTradeStatesDirty {
stateExchanges.lendingTradeStatesDirty[orderId] = struct{}{} stateExchanges.lendingTradeStatesDirty[orderId] = struct{}{}
} }
for time, orderList := range self.liquidationTimeStates { for time, orderList := range le.liquidationTimeStates {
stateExchanges.liquidationTimeStates[time] = orderList.deepCopy(db, self.MarkLiquidationTimeDirty) stateExchanges.liquidationTimeStates[time] = orderList.deepCopy(db, le.MarkLiquidationTimeDirty)
} }
for time := range self.liquidationTimestatesDirty { for time := range le.liquidationTimestatesDirty {
stateExchanges.liquidationTimestatesDirty[time] = struct{}{} stateExchanges.liquidationTimestatesDirty[time] = struct{}{}
} }
return stateExchanges return stateExchanges
} }
// Returns the address of the contract/tradeId // Returns the address of the contract/tradeId
func (self *lendingExchangeState) Hash() common.Hash { func (le *lendingExchangeState) Hash() common.Hash {
return self.lendingBook return le.lendingBook
} }
func (self *lendingExchangeState) setNonce(nonce uint64) { func (le *lendingExchangeState) setNonce(nonce uint64) {
self.data.Nonce = nonce le.data.Nonce = nonce
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) Nonce() uint64 { func (le *lendingExchangeState) Nonce() uint64 {
return self.data.Nonce return le.data.Nonce
} }
func (self *lendingExchangeState) setTradeNonce(nonce uint64) { func (le *lendingExchangeState) setTradeNonce(nonce uint64) {
self.data.TradeNonce = nonce le.data.TradeNonce = nonce
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) TradeNonce() uint64 {
return self.data.TradeNonce func (le *lendingExchangeState) TradeNonce() uint64 {
return le.data.TradeNonce
} }
func (self *lendingExchangeState) removeInvestingOrderList(db Database, stateOrderList *itemListState) { func (le *lendingExchangeState) removeInvestingOrderList(db Database, stateOrderList *itemListState) {
self.setError(self.investingTrie.TryDelete(stateOrderList.key[:])) le.setError(le.investingTrie.TryDelete(stateOrderList.key[:]))
} }
func (self *lendingExchangeState) removeBorrowingOrderList(db Database, stateOrderList *itemListState) { func (le *lendingExchangeState) removeBorrowingOrderList(db Database, stateOrderList *itemListState) {
self.setError(self.borrowingTrie.TryDelete(stateOrderList.key[:])) le.setError(le.borrowingTrie.TryDelete(stateOrderList.key[:]))
} }
func (self *lendingExchangeState) createInvestingOrderList(db Database, price common.Hash) (newobj *itemListState) { func (le *lendingExchangeState) createInvestingOrderList(db Database, price common.Hash) (newobj *itemListState) {
newobj = newItemListState(self.lendingBook, price, itemList{Volume: Zero}, self.MarkInvestingDirty) newobj = newItemListState(le.lendingBook, price, itemList{Volume: Zero}, le.MarkInvestingDirty)
self.investingStates[price] = newobj le.investingStates[price] = newobj
self.investingStatesDirty[price] = struct{}{} le.investingStatesDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err)) panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
} }
self.setError(self.getInvestingTrie(db).TryUpdate(price[:], data)) le.setError(le.getInvestingTrie(db).TryUpdate(price[:], data))
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
return newobj return newobj
} }
func (self *lendingExchangeState) MarkBorrowingDirty(price common.Hash) { func (le *lendingExchangeState) MarkBorrowingDirty(price common.Hash) {
self.borrowingStatesDirty[price] = struct{}{} le.borrowingStatesDirty[price] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) MarkInvestingDirty(price common.Hash) { func (le *lendingExchangeState) MarkInvestingDirty(price common.Hash) {
self.investingStatesDirty[price] = struct{}{} le.investingStatesDirty[price] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) MarkLendingItemDirty(lending common.Hash) { func (le *lendingExchangeState) MarkLendingItemDirty(lending common.Hash) {
self.lendingItemStatesDirty[lending] = struct{}{} le.lendingItemStatesDirty[lending] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) MarkLendingTradeDirty(tradeId common.Hash) { func (le *lendingExchangeState) MarkLendingTradeDirty(tradeId common.Hash) {
self.lendingTradeStatesDirty[tradeId] = struct{}{} le.lendingTradeStatesDirty[tradeId] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) MarkLiquidationTimeDirty(orderId common.Hash) { func (le *lendingExchangeState) MarkLiquidationTimeDirty(orderId common.Hash) {
self.liquidationTimestatesDirty[orderId] = struct{}{} le.liquidationTimestatesDirty[orderId] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
} }
func (self *lendingExchangeState) createBorrowingOrderList(db Database, price common.Hash) (newobj *itemListState) { func (le *lendingExchangeState) createBorrowingOrderList(db Database, price common.Hash) (newobj *itemListState) {
newobj = newItemListState(self.lendingBook, price, itemList{Volume: Zero}, self.MarkBorrowingDirty) newobj = newItemListState(le.lendingBook, price, itemList{Volume: Zero}, le.MarkBorrowingDirty)
self.borrowingStates[price] = newobj le.borrowingStates[price] = newobj
self.borrowingStatesDirty[price] = struct{}{} le.borrowingStatesDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err)) panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
} }
self.setError(self.getBorrowingTrie(db).TryUpdate(price[:], data)) le.setError(le.getBorrowingTrie(db).TryUpdate(price[:], data))
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.Hash()) le.onDirty(le.Hash())
self.onDirty = nil le.onDirty = nil
} }
return newobj return newobj
} }
func (self *lendingExchangeState) createLendingItem(db Database, orderId common.Hash, order LendingItem) (newobj *lendingItemState) { func (le *lendingExchangeState) createLendingItem(db Database, orderId common.Hash, order LendingItem) (newobj *lendingItemState) {
newobj = newLendinItemState(self.lendingBook, orderId, order, self.MarkLendingItemDirty) newobj = newLendinItemState(le.lendingBook, orderId, order, le.MarkLendingItemDirty)
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.LendingId)) orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.LendingId))
self.lendingItemStates[orderIdHash] = newobj le.lendingItemStates[orderIdHash] = newobj
self.lendingItemStatesDirty[orderIdHash] = struct{}{} le.lendingItemStatesDirty[orderIdHash] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.lendingBook) le.onDirty(le.lendingBook)
self.onDirty = nil le.onDirty = nil
} }
return newobj return newobj
} }
func (self *lendingExchangeState) createLiquidationTime(db Database, time common.Hash) (newobj *liquidationTimeState) { func (le *lendingExchangeState) createLiquidationTime(db Database, time common.Hash) (newobj *liquidationTimeState) {
newobj = newLiquidationTimeState(time, self.lendingBook, itemList{Volume: Zero}, self.MarkLiquidationTimeDirty) newobj = newLiquidationTimeState(time, le.lendingBook, itemList{Volume: Zero}, le.MarkLiquidationTimeDirty)
self.liquidationTimeStates[time] = newobj le.liquidationTimeStates[time] = newobj
self.liquidationTimestatesDirty[time] = struct{}{} le.liquidationTimestatesDirty[time] = struct{}{}
data, err := rlp.EncodeToBytes(newobj) data, err := rlp.EncodeToBytes(newobj)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode liquidation time at %x: %v", time[:], err)) panic(fmt.Errorf("can't encode liquidation time at %x: %v", time[:], err))
} }
self.setError(self.getLiquidationTimeTrie(db).TryUpdate(time[:], data)) le.setError(le.getLiquidationTimeTrie(db).TryUpdate(time[:], data))
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.lendingBook) le.onDirty(le.lendingBook)
self.onDirty = nil le.onDirty = nil
} }
return newobj return newobj
} }
func (self *lendingExchangeState) insertLendingTrade(tradeId common.Hash, order LendingTrade) (newobj *lendingTradeState) { func (le *lendingExchangeState) insertLendingTrade(tradeId common.Hash, order LendingTrade) (newobj *lendingTradeState) {
newobj = newLendingTradeState(self.lendingBook, tradeId, order, self.MarkLendingTradeDirty) newobj = newLendingTradeState(le.lendingBook, tradeId, order, le.MarkLendingTradeDirty)
self.lendingTradeStates[tradeId] = newobj le.lendingTradeStates[tradeId] = newobj
self.lendingTradeStatesDirty[tradeId] = struct{}{} le.lendingTradeStatesDirty[tradeId] = struct{}{}
if self.onDirty != nil { if le.onDirty != nil {
self.onDirty(self.lendingBook) le.onDirty(le.lendingBook)
self.onDirty = nil le.onDirty = nil
} }
return newobj return newobj
} }

View file

@ -31,8 +31,8 @@ type lendingItemState struct {
onDirty func(orderId common.Hash) // Callback method to mark a state object newly dirty onDirty func(orderId common.Hash) // Callback method to mark a state object newly dirty
} }
func (s *lendingItemState) empty() bool { func (li *lendingItemState) empty() bool {
return s.data.Quantity == nil || s.data.Quantity.Cmp(Zero) == 0 return li.data.Quantity == nil || li.data.Quantity.Cmp(Zero) == 0
} }
func newLendinItemState(orderBook common.Hash, orderId common.Hash, data LendingItem, onDirty func(orderId common.Hash)) *lendingItemState { func newLendinItemState(orderBook common.Hash, orderId common.Hash, data LendingItem, onDirty func(orderId common.Hash)) *lendingItemState {
@ -45,23 +45,23 @@ func newLendinItemState(orderBook common.Hash, orderId common.Hash, data Lending
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *lendingItemState) EncodeRLP(w io.Writer) error { func (li *lendingItemState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, li.data)
} }
func (self *lendingItemState) deepCopy(onDirty func(orderId common.Hash)) *lendingItemState { func (li *lendingItemState) deepCopy(onDirty func(orderId common.Hash)) *lendingItemState {
stateOrderList := newLendinItemState(self.orderBook, self.orderId, self.data, onDirty) stateOrderList := newLendinItemState(li.orderBook, li.orderId, li.data, onDirty)
return stateOrderList return stateOrderList
} }
func (self *lendingItemState) setVolume(volume *big.Int) { func (li *lendingItemState) setVolume(volume *big.Int) {
self.data.Quantity = volume li.data.Quantity = volume
if self.onDirty != nil { if li.onDirty != nil {
self.onDirty(self.orderId) li.onDirty(li.orderId)
self.onDirty = nil li.onDirty = nil
} }
} }
func (self *lendingItemState) Quantity() *big.Int { func (li *lendingItemState) Quantity() *big.Int {
return self.data.Quantity return li.data.Quantity
} }

View file

@ -17,10 +17,11 @@
package lendingstate package lendingstate
import ( import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
"io" "io"
"math/big" "math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
) )
type lendingTradeState struct { type lendingTradeState struct {
@ -30,8 +31,8 @@ type lendingTradeState struct {
onDirty func(orderId common.Hash) // Callback method to mark a state object newly dirty onDirty func(orderId common.Hash) // Callback method to mark a state object newly dirty
} }
func (s *lendingTradeState) empty() bool { func (lt *lendingTradeState) empty() bool {
return s.data.Amount.Sign() == 0 return lt.data.Amount.Sign() == 0
} }
func newLendingTradeState(orderBook common.Hash, tradeId common.Hash, data LendingTrade, onDirty func(orderId common.Hash)) *lendingTradeState { func newLendingTradeState(orderBook common.Hash, tradeId common.Hash, data LendingTrade, onDirty func(orderId common.Hash)) *lendingTradeState {
@ -44,35 +45,35 @@ func newLendingTradeState(orderBook common.Hash, tradeId common.Hash, data Lendi
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
func (c *lendingTradeState) EncodeRLP(w io.Writer) error { func (lt *lendingTradeState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data) return rlp.Encode(w, lt.data)
} }
func (self *lendingTradeState) deepCopy(onDirty func(orderId common.Hash)) *lendingTradeState { func (lt *lendingTradeState) deepCopy(onDirty func(orderId common.Hash)) *lendingTradeState {
stateOrderList := newLendingTradeState(self.orderBook, self.tradeId, self.data, onDirty) stateOrderList := newLendingTradeState(lt.orderBook, lt.tradeId, lt.data, onDirty)
return stateOrderList return stateOrderList
} }
func (self *lendingTradeState) SetCollateralLockedAmount(amount *big.Int) { func (lt *lendingTradeState) SetCollateralLockedAmount(amount *big.Int) {
self.data.CollateralLockedAmount = amount lt.data.CollateralLockedAmount = amount
if self.onDirty != nil { if lt.onDirty != nil {
self.onDirty(self.tradeId) lt.onDirty(lt.tradeId)
self.onDirty = nil lt.onDirty = nil
} }
} }
func (self *lendingTradeState) SetLiquidationPrice(price *big.Int) { func (lt *lendingTradeState) SetLiquidationPrice(price *big.Int) {
self.data.LiquidationPrice = price lt.data.LiquidationPrice = price
if self.onDirty != nil { if lt.onDirty != nil {
self.onDirty(self.tradeId) lt.onDirty(lt.tradeId)
self.onDirty = nil lt.onDirty = nil
} }
} }
func (self *lendingTradeState) SetAmount(amount *big.Int) { func (lt *lendingTradeState) SetAmount(amount *big.Int) {
self.data.Amount = amount lt.data.Amount = amount
if self.onDirty != nil { if lt.onDirty != nil {
self.onDirty(self.tradeId) lt.onDirty(lt.tradeId)
self.onDirty = nil lt.onDirty = nil
} }
} }

View file

@ -19,11 +19,12 @@ package lendingstate
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
"io"
"math/big"
) )
type liquidationTimeState struct { type liquidationTimeState struct {
@ -47,8 +48,8 @@ type liquidationTimeState struct {
onDirty func(time common.Hash) // Callback method to mark a state object newly dirty onDirty func(time common.Hash) // Callback method to mark a state object newly dirty
} }
func (s *liquidationTimeState) empty() bool { func (lt *liquidationTimeState) empty() bool {
return s.data.Volume == nil || s.data.Volume.Sign() == 0 return lt.data.Volume == nil || lt.data.Volume.Sign() == 0
} }
func newLiquidationTimeState(time common.Hash, lendingBook common.Hash, data itemList, onDirty func(time common.Hash)) *liquidationTimeState { func newLiquidationTimeState(time common.Hash, lendingBook common.Hash, data itemList, onDirty func(time common.Hash)) *liquidationTimeState {
@ -62,59 +63,59 @@ func newLiquidationTimeState(time common.Hash, lendingBook common.Hash, data ite
} }
} }
func (self *liquidationTimeState) EncodeRLP(w io.Writer) error { func (lt *liquidationTimeState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, self.data) return rlp.Encode(w, lt.data)
} }
func (self *liquidationTimeState) setError(err error) { func (lt *liquidationTimeState) setError(err error) {
if self.dbErr == nil { if lt.dbErr == nil {
self.dbErr = err lt.dbErr = err
} }
} }
func (self *liquidationTimeState) getTrie(db Database) Trie { func (lt *liquidationTimeState) getTrie(db Database) Trie {
if self.trie == nil { if lt.trie == nil {
var err error var err error
self.trie, err = db.OpenStorageTrie(self.lendingBook, self.data.Root) lt.trie, err = db.OpenStorageTrie(lt.lendingBook, lt.data.Root)
if err != nil { if err != nil {
self.trie, _ = db.OpenStorageTrie(self.time, EmptyHash) lt.trie, _ = db.OpenStorageTrie(lt.time, EmptyHash)
self.setError(fmt.Errorf("can't create storage trie: %v", err)) lt.setError(fmt.Errorf("can't create storage trie: %v", err))
} }
} }
return self.trie return lt.trie
} }
func (self *liquidationTimeState) Exist(db Database, tradeId common.Hash) bool { func (lt *liquidationTimeState) Exist(db Database, tradeId common.Hash) bool {
amount, exists := self.cachedStorage[tradeId] amount, exists := lt.cachedStorage[tradeId]
if exists { if exists {
return true return true
} }
// Load from DB in case it is missing. // Load from DB in case it is missing.
enc, err := self.getTrie(db).TryGet(tradeId[:]) enc, err := lt.getTrie(db).TryGet(tradeId[:])
if err != nil { if err != nil {
self.setError(err) lt.setError(err)
return false return false
} }
if len(enc) > 0 { if len(enc) > 0 {
_, content, _, err := rlp.Split(enc) _, content, _, err := rlp.Split(enc)
if err != nil { if err != nil {
self.setError(err) lt.setError(err)
} }
amount.SetBytes(content) amount.SetBytes(content)
} }
if (amount != common.Hash{}) { if (amount != common.Hash{}) {
self.cachedStorage[tradeId] = amount lt.cachedStorage[tradeId] = amount
} }
return true return true
} }
func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash { func (lt *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
tradeIds := []common.Hash{} tradeIds := []common.Hash{}
lendingBookTrie := self.getTrie(db) lendingBookTrie := lt.getTrie(db)
if lendingBookTrie == nil { if lendingBookTrie == nil {
return tradeIds return tradeIds
} }
for id, value := range self.cachedStorage { for id, value := range lt.cachedStorage {
if !common.EmptyHash(value) { if !common.EmptyHash(value) {
tradeIds = append(tradeIds, id) tradeIds = append(tradeIds, id)
} }
@ -122,7 +123,7 @@ func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil)) orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil))
for orderListIt.Next() { for orderListIt.Next() {
id := common.BytesToHash(orderListIt.Key) id := common.BytesToHash(orderListIt.Key)
if _, exist := self.cachedStorage[id]; exist { if _, exist := lt.cachedStorage[id]; exist {
continue continue
} }
tradeIds = append(tradeIds, id) tradeIds = append(tradeIds, id)
@ -130,83 +131,83 @@ func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
return tradeIds return tradeIds
} }
func (self *liquidationTimeState) insertTradeId(db Database, tradeId common.Hash) { func (lt *liquidationTimeState) insertTradeId(db Database, tradeId common.Hash) {
self.setTradeId(tradeId, tradeId) lt.setTradeId(tradeId, tradeId)
self.setError(self.getTrie(db).TryUpdate(tradeId[:], tradeId[:])) lt.setError(lt.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
} }
func (self *liquidationTimeState) removeTradeId(db Database, tradeId common.Hash) { func (lt *liquidationTimeState) removeTradeId(db Database, tradeId common.Hash) {
tr := self.getTrie(db) tr := lt.getTrie(db)
self.setError(tr.TryDelete(tradeId[:])) lt.setError(tr.TryDelete(tradeId[:]))
self.setTradeId(tradeId, EmptyHash) lt.setTradeId(tradeId, EmptyHash)
} }
func (self *liquidationTimeState) setTradeId(tradeId common.Hash, value common.Hash) { func (lt *liquidationTimeState) setTradeId(tradeId common.Hash, value common.Hash) {
self.cachedStorage[tradeId] = value lt.cachedStorage[tradeId] = value
self.dirtyStorage[tradeId] = value lt.dirtyStorage[tradeId] = value
if self.onDirty != nil { if lt.onDirty != nil {
self.onDirty(self.lendingBook) lt.onDirty(lt.lendingBook)
self.onDirty = nil lt.onDirty = nil
} }
} }
func (self *liquidationTimeState) updateTrie(db Database) Trie { func (lt *liquidationTimeState) updateTrie(db Database) Trie {
tr := self.getTrie(db) tr := lt.getTrie(db)
for key, value := range self.dirtyStorage { for key, value := range lt.dirtyStorage {
delete(self.dirtyStorage, key) delete(lt.dirtyStorage, key)
if value == EmptyHash { if value == EmptyHash {
self.setError(tr.TryDelete(key[:])) lt.setError(tr.TryDelete(key[:]))
continue continue
} }
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00")) v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
self.setError(tr.TryUpdate(key[:], v)) lt.setError(tr.TryUpdate(key[:], v))
} }
return tr return tr
} }
func (self *liquidationTimeState) updateRoot(db Database) error { func (lt *liquidationTimeState) updateRoot(db Database) error {
self.updateTrie(db) lt.updateTrie(db)
if self.dbErr != nil { if lt.dbErr != nil {
return self.dbErr return lt.dbErr
} }
root, err := self.trie.Commit(nil) root, err := lt.trie.Commit(nil)
if err == nil { if err == nil {
self.data.Root = root lt.data.Root = root
} }
return err return err
} }
func (self *liquidationTimeState) deepCopy(db *LendingStateDB, onDirty func(time common.Hash)) *liquidationTimeState { func (lt *liquidationTimeState) deepCopy(db *LendingStateDB, onDirty func(time common.Hash)) *liquidationTimeState {
stateLendingBook := newLiquidationTimeState(self.lendingBook, self.time, self.data, onDirty) stateLendingBook := newLiquidationTimeState(lt.lendingBook, lt.time, lt.data, onDirty)
if self.trie != nil { if lt.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(self.trie) stateLendingBook.trie = db.db.CopyTrie(lt.trie)
} }
for key, value := range self.dirtyStorage { for key, value := range lt.dirtyStorage {
stateLendingBook.dirtyStorage[key] = value stateLendingBook.dirtyStorage[key] = value
} }
for key, value := range self.cachedStorage { for key, value := range lt.cachedStorage {
stateLendingBook.cachedStorage[key] = value stateLendingBook.cachedStorage[key] = value
} }
return stateLendingBook return stateLendingBook
} }
func (c *liquidationTimeState) AddVolume(amount *big.Int) { func (lt *liquidationTimeState) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount)) lt.setVolume(new(big.Int).Add(lt.data.Volume, amount))
} }
func (c *liquidationTimeState) subVolume(amount *big.Int) { func (lt *liquidationTimeState) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount)) lt.setVolume(new(big.Int).Sub(lt.data.Volume, amount))
} }
func (self *liquidationTimeState) setVolume(volume *big.Int) { func (lt *liquidationTimeState) setVolume(volume *big.Int) {
self.data.Volume = volume lt.data.Volume = volume
if self.onDirty != nil { if lt.onDirty != nil {
self.onDirty(self.lendingBook) lt.onDirty(lt.lendingBook)
self.onDirty = nil lt.onDirty = nil
} }
} }
func (self *liquidationTimeState) Volume() *big.Int { func (lt *liquidationTimeState) Volume() *big.Int {
return self.data.Volume return lt.data.Volume
} }

View file

@ -73,39 +73,39 @@ func New(root common.Hash, db Database) (*LendingStateDB, error) {
} }
// setError remembers the first non-nil error it is called with. // setError remembers the first non-nil error it is called with.
func (self *LendingStateDB) setError(err error) { func (ls *LendingStateDB) setError(err error) {
if self.dbErr == nil { if ls.dbErr == nil {
self.dbErr = err ls.dbErr = err
} }
} }
func (self *LendingStateDB) Error() error { func (ls *LendingStateDB) Error() error {
return self.dbErr return ls.dbErr
} }
// Exist reports whether the given tradeId address exists in the state. // Exist reports whether the given tradeId address exists in the state.
// Notably this also returns true for suicided lenddinges. // Notably this also returns true for suicided lenddinges.
func (self *LendingStateDB) Exist(addr common.Hash) bool { func (ls *LendingStateDB) Exist(addr common.Hash) bool {
return self.getLendingExchange(addr) != nil return ls.getLendingExchange(addr) != nil
} }
// Empty returns whether the state object is either non-existent // Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0) // or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *LendingStateDB) Empty(addr common.Hash) bool { func (ls *LendingStateDB) Empty(addr common.Hash) bool {
so := self.getLendingExchange(addr) so := ls.getLendingExchange(addr)
return so == nil || so.empty() return so == nil || so.empty()
} }
func (self *LendingStateDB) GetNonce(addr common.Hash) uint64 { func (ls *LendingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := self.getLendingExchange(addr) stateObject := ls.getLendingExchange(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Nonce() return stateObject.Nonce()
} }
return 0 return 0
} }
func (self *LendingStateDB) GetTradeNonce(addr common.Hash) uint64 { func (ls *LendingStateDB) GetTradeNonce(addr common.Hash) uint64 {
stateObject := self.getLendingExchange(addr) stateObject := ls.getLendingExchange(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.TradeNonce() return stateObject.TradeNonce()
} }
@ -113,14 +113,14 @@ func (self *LendingStateDB) GetTradeNonce(addr common.Hash) uint64 {
} }
// Database retrieves the low level database supporting the lower level trie ops. // Database retrieves the low level database supporting the lower level trie ops.
func (self *LendingStateDB) Database() Database { func (ls *LendingStateDB) Database() Database {
return self.db return ls.db
} }
func (self *LendingStateDB) SetNonce(addr common.Hash, nonce uint64) { func (ls *LendingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := self.GetOrNewLendingExchangeObject(addr) stateObject := ls.GetOrNewLendingExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, nonceChange{ ls.journal = append(ls.journal, nonceChange{
hash: addr, hash: addr,
prev: stateObject.Nonce(), prev: stateObject.Nonce(),
}) })
@ -128,10 +128,10 @@ func (self *LendingStateDB) SetNonce(addr common.Hash, nonce uint64) {
} }
} }
func (self *LendingStateDB) SetTradeNonce(addr common.Hash, nonce uint64) { func (ls *LendingStateDB) SetTradeNonce(addr common.Hash, nonce uint64) {
stateObject := self.GetOrNewLendingExchangeObject(addr) stateObject := ls.GetOrNewLendingExchangeObject(addr)
if stateObject != nil { if stateObject != nil {
self.journal = append(self.journal, tradeNonceChange{ ls.journal = append(ls.journal, tradeNonceChange{
hash: addr, hash: addr,
prev: stateObject.TradeNonce(), prev: stateObject.TradeNonce(),
}) })
@ -139,45 +139,45 @@ func (self *LendingStateDB) SetTradeNonce(addr common.Hash, nonce uint64) {
} }
} }
func (self *LendingStateDB) InsertLendingItem(orderBook common.Hash, orderId common.Hash, order LendingItem) { func (ls *LendingStateDB) InsertLendingItem(orderBook common.Hash, orderId common.Hash, order LendingItem) {
interestHash := common.BigToHash(order.Interest) interestHash := common.BigToHash(order.Interest)
stateExchange := self.getLendingExchange(orderBook) stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil { if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook) stateExchange = ls.createLendingExchangeObject(orderBook)
} }
var stateOrderList *itemListState var stateOrderList *itemListState
switch order.Side { switch order.Side {
case Investing: case Investing:
stateOrderList = stateExchange.getInvestingOrderList(self.db, interestHash) stateOrderList = stateExchange.getInvestingOrderList(ls.db, interestHash)
if stateOrderList == nil { if stateOrderList == nil {
stateOrderList = stateExchange.createInvestingOrderList(self.db, interestHash) stateOrderList = stateExchange.createInvestingOrderList(ls.db, interestHash)
} }
case Borrowing: case Borrowing:
stateOrderList = stateExchange.getBorrowingOrderList(self.db, interestHash) stateOrderList = stateExchange.getBorrowingOrderList(ls.db, interestHash)
if stateOrderList == nil { if stateOrderList == nil {
stateOrderList = stateExchange.createBorrowingOrderList(self.db, interestHash) stateOrderList = stateExchange.createBorrowingOrderList(ls.db, interestHash)
} }
default: default:
return return
} }
self.journal = append(self.journal, insertOrder{ ls.journal = append(ls.journal, insertOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderId, orderId: orderId,
order: &order, order: &order,
}) })
stateExchange.createLendingItem(self.db, orderId, order) stateExchange.createLendingItem(ls.db, orderId, order)
stateOrderList.insertLendingItem(self.db, orderId, common.BigToHash(order.Quantity)) stateOrderList.insertLendingItem(ls.db, orderId, common.BigToHash(order.Quantity))
stateOrderList.AddVolume(order.Quantity) stateOrderList.AddVolume(order.Quantity)
} }
func (self *LendingStateDB) InsertTradingItem(orderBook common.Hash, tradeId uint64, order LendingTrade) { func (ls *LendingStateDB) InsertTradingItem(orderBook common.Hash, tradeId uint64, order LendingTrade) {
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
stateExchange := self.getLendingExchange(orderBook) stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil { if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook) stateExchange = ls.createLendingExchangeObject(orderBook)
} }
prvTrade := self.GetLendingTrade(orderBook, tradeIdHash) prvTrade := ls.GetLendingTrade(orderBook, tradeIdHash)
self.journal = append(self.journal, insertTrading{ ls.journal = append(ls.journal, insertTrading{
orderBook: orderBook, orderBook: orderBook,
tradeId: tradeId, tradeId: tradeId,
prvTrade: &prvTrade, prvTrade: &prvTrade,
@ -185,88 +185,90 @@ func (self *LendingStateDB) InsertTradingItem(orderBook common.Hash, tradeId uin
stateExchange.insertLendingTrade(tradeIdHash, order) stateExchange.insertLendingTrade(tradeIdHash, order)
} }
func (self *LendingStateDB) UpdateLiquidationPrice(orderBook common.Hash, tradeId uint64, price *big.Int) { func (ls *LendingStateDB) UpdateLiquidationPrice(orderBook common.Hash, tradeId uint64, price *big.Int) {
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
stateExchange := self.getLendingExchange(orderBook) stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil { if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook) stateExchange = ls.createLendingExchangeObject(orderBook)
} }
stateLendingTrade := stateExchange.getLendingTrade(self.db, tradeIdHash) stateLendingTrade := stateExchange.getLendingTrade(ls.db, tradeIdHash)
self.journal = append(self.journal, liquidationPriceChange{ ls.journal = append(ls.journal, liquidationPriceChange{
orderBook: orderBook, orderBook: orderBook,
tradeId: tradeIdHash, tradeId: tradeIdHash,
prev: stateLendingTrade.data.LiquidationPrice, prev: stateLendingTrade.data.LiquidationPrice,
}) })
stateLendingTrade.SetLiquidationPrice(price) stateLendingTrade.SetLiquidationPrice(price)
} }
func (self *LendingStateDB) UpdateCollateralLockedAmount(orderBook common.Hash, tradeId uint64, amount *big.Int) {
func (ls *LendingStateDB) UpdateCollateralLockedAmount(orderBook common.Hash, tradeId uint64, amount *big.Int) {
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
stateExchange := self.getLendingExchange(orderBook) stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil { if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook) stateExchange = ls.createLendingExchangeObject(orderBook)
} }
stateLendingTrade := stateExchange.getLendingTrade(self.db, tradeIdHash) stateLendingTrade := stateExchange.getLendingTrade(ls.db, tradeIdHash)
self.journal = append(self.journal, collateralLockedAmount{ ls.journal = append(ls.journal, collateralLockedAmount{
orderBook: orderBook, orderBook: orderBook,
tradeId: tradeIdHash, tradeId: tradeIdHash,
prev: stateLendingTrade.data.CollateralLockedAmount, prev: stateLendingTrade.data.CollateralLockedAmount,
}) })
stateLendingTrade.SetCollateralLockedAmount(amount) stateLendingTrade.SetCollateralLockedAmount(amount)
} }
func (self *LendingStateDB) GetLendingOrder(orderBook common.Hash, orderId common.Hash) LendingItem {
stateObject := self.GetOrNewLendingExchangeObject(orderBook) func (ls *LendingStateDB) GetLendingOrder(orderBook common.Hash, orderId common.Hash) LendingItem {
stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return EmptyLendingOrder return EmptyLendingOrder
} }
stateOrderItem := stateObject.getLendingItem(self.db, orderId) stateOrderItem := stateObject.getLendingItem(ls.db, orderId)
if stateOrderItem == nil { if stateOrderItem == nil {
return EmptyLendingOrder return EmptyLendingOrder
} }
return stateOrderItem.data return stateOrderItem.data
} }
func (self *LendingStateDB) GetLendingTrade(orderBook common.Hash, tradeId common.Hash) LendingTrade { func (ls *LendingStateDB) GetLendingTrade(orderBook common.Hash, tradeId common.Hash) LendingTrade {
stateObject := self.GetOrNewLendingExchangeObject(orderBook) stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return EmptyLendingTrade return EmptyLendingTrade
} }
stateOrderItem := stateObject.getLendingTrade(self.db, tradeId) stateOrderItem := stateObject.getLendingTrade(ls.db, tradeId)
if stateOrderItem == nil || stateOrderItem.empty() { if stateOrderItem == nil || stateOrderItem.empty() {
return EmptyLendingTrade return EmptyLendingTrade
} }
return stateOrderItem.data return stateOrderItem.data
} }
func (self *LendingStateDB) SubAmountLendingItem(orderBook common.Hash, orderId common.Hash, price *big.Int, amount *big.Int, side string) error { func (ls *LendingStateDB) SubAmountLendingItem(orderBook common.Hash, orderId common.Hash, price *big.Int, amount *big.Int, side string) error {
priceHash := common.BigToHash(price) priceHash := common.BigToHash(price)
lendingExchange := self.GetOrNewLendingExchangeObject(orderBook) lendingExchange := ls.GetOrNewLendingExchangeObject(orderBook)
if lendingExchange == nil { if lendingExchange == nil {
return fmt.Errorf("Order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found order book: %s", orderBook.Hex())
} }
var orderList *itemListState var orderList *itemListState
switch side { switch side {
case Investing: case Investing:
orderList = lendingExchange.getInvestingOrderList(self.db, priceHash) orderList = lendingExchange.getInvestingOrderList(ls.db, priceHash)
case Borrowing: case Borrowing:
orderList = lendingExchange.getBorrowingOrderList(self.db, priceHash) orderList = lendingExchange.getBorrowingOrderList(ls.db, priceHash)
default: default:
return fmt.Errorf("Order type not found : %s ", side) return fmt.Errorf("not found order type: %s", side)
} }
if orderList == nil || orderList.empty() { if orderList == nil || orderList.empty() {
return fmt.Errorf("Order list empty order book : %s , order id : %s , key : %s ", orderBook, orderId.Hex(), priceHash.Hex()) return fmt.Errorf("empty orderList: order book : %s , order id : %s , key : %s", orderBook, orderId.Hex(), priceHash.Hex())
} }
lendingItem := lendingExchange.getLendingItem(self.db, orderId) lendingItem := lendingExchange.getLendingItem(ls.db, orderId)
if lendingItem == nil || lendingItem.empty() { if lendingItem == nil || lendingItem.empty() {
return fmt.Errorf("Order item empty order book : %s , order id : %s , key : %s ", orderBook, orderId.Hex(), priceHash.Hex()) return fmt.Errorf("empty order item: order book : %s , order id : %s , key : %s", orderBook, orderId.Hex(), priceHash.Hex())
} }
currentAmount := new(big.Int).SetBytes(orderList.GetOrderAmount(self.db, orderId).Bytes()[:]) currentAmount := new(big.Int).SetBytes(orderList.GetOrderAmount(ls.db, orderId).Bytes()[:])
if currentAmount.Cmp(amount) < 0 { if currentAmount.Cmp(amount) < 0 {
return fmt.Errorf("Order amount not enough : %s , have : %d , want : %d ", orderId.Hex(), currentAmount, amount) return fmt.Errorf("not enough order amount %s: have : %d , want : %d", orderId.Hex(), currentAmount, amount)
} }
self.journal = append(self.journal, subAmountOrder{ ls.journal = append(ls.journal, subAmountOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderId, orderId: orderId,
order: self.GetLendingOrder(orderBook, orderId), order: ls.GetLendingOrder(orderBook, orderId),
amount: amount, amount: amount,
}) })
newAmount := new(big.Int).Sub(currentAmount, amount) newAmount := new(big.Int).Sub(currentAmount, amount)
@ -274,77 +276,77 @@ func (self *LendingStateDB) SubAmountLendingItem(orderBook common.Hash, orderId
log.Debug("SubAmountOrderItem", "tradeId", orderId.Hex(), "side", side, "key", price.Uint64(), "amount", amount.Uint64(), "new amount", newAmount.Uint64()) log.Debug("SubAmountOrderItem", "tradeId", orderId.Hex(), "side", side, "key", price.Uint64(), "amount", amount.Uint64(), "new amount", newAmount.Uint64())
orderList.subVolume(amount) orderList.subVolume(amount)
if newAmount.Sign() == 0 { if newAmount.Sign() == 0 {
orderList.removeOrderItem(self.db, orderId) orderList.removeOrderItem(ls.db, orderId)
} else { } else {
orderList.setOrderItem(orderId, common.BigToHash(newAmount)) orderList.setOrderItem(orderId, common.BigToHash(newAmount))
} }
if orderList.empty() { if orderList.empty() {
switch side { switch side {
case Investing: case Investing:
lendingExchange.removeInvestingOrderList(self.db, orderList) lendingExchange.removeInvestingOrderList(ls.db, orderList)
case Borrowing: case Borrowing:
lendingExchange.removeBorrowingOrderList(self.db, orderList) lendingExchange.removeBorrowingOrderList(ls.db, orderList)
default: default:
} }
} }
return nil return nil
} }
func (self *LendingStateDB) CancelLendingOrder(orderBook common.Hash, order *LendingItem) error { func (ls *LendingStateDB) CancelLendingOrder(orderBook common.Hash, order *LendingItem) error {
interestHash := common.BigToHash(order.Interest) interestHash := common.BigToHash(order.Interest)
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.LendingId)) orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.LendingId))
stateObject := self.GetOrNewLendingExchangeObject(orderBook) stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return fmt.Errorf("Order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found order book: %s", orderBook.Hex())
} }
lendingItem := stateObject.getLendingItem(self.db, orderIdHash) lendingItem := stateObject.getLendingItem(ls.db, orderIdHash)
var orderList *itemListState var orderList *itemListState
switch lendingItem.data.Side { switch lendingItem.data.Side {
case Investing: case Investing:
orderList = stateObject.getInvestingOrderList(self.db, interestHash) orderList = stateObject.getInvestingOrderList(ls.db, interestHash)
case Borrowing: case Borrowing:
orderList = stateObject.getBorrowingOrderList(self.db, interestHash) orderList = stateObject.getBorrowingOrderList(ls.db, interestHash)
default: default:
return fmt.Errorf("Order side not found : %s ", order.Side) return fmt.Errorf("not found order side: %s", order.Side)
} }
if orderList == nil || orderList.empty() { if orderList == nil || orderList.empty() {
return fmt.Errorf("Order list empty order book : %s , order id : %s , key : %s ", orderBook, orderIdHash.Hex(), interestHash.Hex()) return fmt.Errorf("empty OrderList: order book : %s , order id : %s , key : %s", orderBook, orderIdHash.Hex(), interestHash.Hex())
} }
if lendingItem == nil || lendingItem.empty() { if lendingItem == nil || lendingItem.empty() {
return fmt.Errorf("Order item empty order book : %s , order id : %s , key : %s ", orderBook, orderIdHash.Hex(), interestHash.Hex()) return fmt.Errorf("empty order item: order book : %s , order id : %s , key : %s", orderBook, orderIdHash.Hex(), interestHash.Hex())
} }
if lendingItem.data.UserAddress != order.UserAddress { if lendingItem.data.UserAddress != order.UserAddress {
return fmt.Errorf("Error Order User Address mismatch when cancel order book : %s , order id : %s , got : %s , expect : %s ", orderBook, orderIdHash.Hex(), lendingItem.data.UserAddress.Hex(), order.UserAddress.Hex()) return fmt.Errorf("error Order UserAddress mismatch when cancel order book: %s , order id : %s , got : %s , expect : %s", orderBook, orderIdHash.Hex(), lendingItem.data.UserAddress.Hex(), order.UserAddress.Hex())
} }
self.journal = append(self.journal, cancelOrder{ ls.journal = append(ls.journal, cancelOrder{
orderBook: orderBook, orderBook: orderBook,
orderId: orderIdHash, orderId: orderIdHash,
order: self.GetLendingOrder(orderBook, orderIdHash), order: ls.GetLendingOrder(orderBook, orderIdHash),
}) })
lendingItem.setVolume(big.NewInt(0)) lendingItem.setVolume(big.NewInt(0))
currentAmount := new(big.Int).SetBytes(orderList.GetOrderAmount(self.db, orderIdHash).Bytes()[:]) currentAmount := new(big.Int).SetBytes(orderList.GetOrderAmount(ls.db, orderIdHash).Bytes()[:])
orderList.subVolume(currentAmount) orderList.subVolume(currentAmount)
orderList.removeOrderItem(self.db, orderIdHash) orderList.removeOrderItem(ls.db, orderIdHash)
if orderList.empty() { if orderList.empty() {
switch order.Side { switch order.Side {
case Investing: case Investing:
stateObject.removeInvestingOrderList(self.db, orderList) stateObject.removeInvestingOrderList(ls.db, orderList)
case Borrowing: case Borrowing:
stateObject.removeBorrowingOrderList(self.db, orderList) stateObject.removeBorrowingOrderList(ls.db, orderList)
default: default:
} }
} }
return nil return nil
} }
func (self *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.Int, *big.Int) { func (ls *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getLendingExchange(orderBook) stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil { if stateObject != nil {
investingHash := stateObject.getBestInvestingInterest(self.db) investingHash := stateObject.getBestInvestingInterest(ls.db)
if common.EmptyHash(investingHash) { if common.EmptyHash(investingHash) {
return Zero, Zero return Zero, Zero
} }
orderList := stateObject.getInvestingOrderList(self.db, investingHash) orderList := stateObject.getInvestingOrderList(ls.db, investingHash)
if orderList == nil { if orderList == nil {
log.Error("order list investing not found", "key", investingHash.Hex()) log.Error("order list investing not found", "key", investingHash.Hex())
return Zero, Zero return Zero, Zero
@ -354,14 +356,14 @@ func (self *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.In
return Zero, Zero return Zero, Zero
} }
func (self *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int, *big.Int) { func (ls *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getLendingExchange(orderBook) stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil { if stateObject != nil {
priceHash := stateObject.getBestBorrowingInterest(self.db) priceHash := stateObject.getBestBorrowingInterest(ls.db)
if common.EmptyHash(priceHash) { if common.EmptyHash(priceHash) {
return Zero, Zero return Zero, Zero
} }
orderList := stateObject.getBorrowingOrderList(self.db, priceHash) orderList := stateObject.getBorrowingOrderList(ls.db, priceHash)
if orderList == nil { if orderList == nil {
log.Error("order list ask not found", "key", priceHash.Hex()) log.Error("order list ask not found", "key", priceHash.Hex())
return Zero, Zero return Zero, Zero
@ -371,52 +373,52 @@ func (self *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int,
return Zero, Zero return Zero, Zero
} }
func (self *LendingStateDB) GetBestLendingIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) { func (ls *LendingStateDB) GetBestLendingIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := self.GetOrNewLendingExchangeObject(orderBook) stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject != nil { if stateObject != nil {
var stateOrderList *itemListState var stateOrderList *itemListState
switch side { switch side {
case Investing: case Investing:
stateOrderList = stateObject.getInvestingOrderList(self.db, common.BigToHash(price)) stateOrderList = stateObject.getInvestingOrderList(ls.db, common.BigToHash(price))
case Borrowing: case Borrowing:
stateOrderList = stateObject.getBorrowingOrderList(self.db, common.BigToHash(price)) stateOrderList = stateObject.getBorrowingOrderList(ls.db, common.BigToHash(price))
default: default:
return EmptyHash, Zero, fmt.Errorf("not found side :%s ", side) return EmptyHash, Zero, fmt.Errorf("not found side: %s", side)
} }
if stateOrderList != nil { if stateOrderList != nil {
key, _, err := stateOrderList.getTrie(self.db).TryGetBestLeftKeyAndValue() key, _, err := stateOrderList.getTrie(ls.db).TryGetBestLeftKeyAndValue()
if err != nil { if err != nil {
return EmptyHash, Zero, err return EmptyHash, Zero, err
} }
orderId := common.BytesToHash(key) orderId := common.BytesToHash(key)
amount := stateOrderList.GetOrderAmount(self.db, orderId) amount := stateOrderList.GetOrderAmount(ls.db, orderId)
return orderId, new(big.Int).SetBytes(amount.Bytes()), nil return orderId, new(big.Int).SetBytes(amount.Bytes()), nil
} }
return EmptyHash, Zero, fmt.Errorf("not found order list with orderBook : %s , key : %d , side :%s ", orderBook.Hex(), price, side) return EmptyHash, Zero, fmt.Errorf("not found order list with orderBook: %s , key : %d , side : %s", orderBook.Hex(), price, side)
} }
return EmptyHash, Zero, fmt.Errorf("not found orderBook : %s ", orderBook.Hex()) return EmptyHash, Zero, fmt.Errorf("not found orderBook: %s", orderBook.Hex())
} }
// updateLendingExchange writes the given object to the trie. // updateLendingExchange writes the given object to the trie.
func (self *LendingStateDB) updateLendingExchange(stateObject *lendingExchangeState) { func (ls *LendingStateDB) updateLendingExchange(stateObject *lendingExchangeState) {
addr := stateObject.Hash() addr := stateObject.Hash()
data, err := rlp.EncodeToBytes(stateObject) data, err := rlp.EncodeToBytes(stateObject)
if err != nil { if err != nil {
panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err)) panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
} }
self.setError(self.trie.TryUpdate(addr[:], data)) ls.setError(ls.trie.TryUpdate(addr[:], data))
} }
// Retrieve a state object given my the address. Returns nil if not found. // Retrieve a state object given my the address. Returns nil if not found.
func (self *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *lendingExchangeState) { func (ls *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *lendingExchangeState) {
// Prefer 'live' objects. // Prefer 'live' objects.
if obj := self.lendingExchangeStates[addr]; obj != nil { if obj := ls.lendingExchangeStates[addr]; obj != nil {
return obj return obj
} }
// Load the object from the database. // Load the object from the database.
enc, err := self.trie.TryGet(addr[:]) enc, err := ls.trie.TryGet(addr[:])
if len(enc) == 0 { if len(enc) == 0 {
self.setError(err) ls.setError(err)
return nil return nil
} }
var data lendingObject var data lendingObject
@ -425,176 +427,176 @@ func (self *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *l
return nil return nil
} }
// Insert into the live set. // Insert into the live set.
obj := newStateExchanges(self, addr, data, self.MarkLendingExchangeObjectDirty) obj := newStateExchanges(ls, addr, data, ls.MarkLendingExchangeObjectDirty)
self.lendingExchangeStates[addr] = obj ls.lendingExchangeStates[addr] = obj
return obj return obj
} }
func (self *LendingStateDB) setLendingExchangeObject(object *lendingExchangeState) { func (ls *LendingStateDB) setLendingExchangeObject(object *lendingExchangeState) {
self.lendingExchangeStates[object.Hash()] = object ls.lendingExchangeStates[object.Hash()] = object
self.lendingExchangeStatesDirty[object.Hash()] = struct{}{} ls.lendingExchangeStatesDirty[object.Hash()] = struct{}{}
} }
// Retrieve a state object or create a new state object if nil. // Retrieve a state object or create a new state object if nil.
func (self *LendingStateDB) GetOrNewLendingExchangeObject(addr common.Hash) *lendingExchangeState { func (ls *LendingStateDB) GetOrNewLendingExchangeObject(addr common.Hash) *lendingExchangeState {
stateExchangeObject := self.getLendingExchange(addr) stateExchangeObject := ls.getLendingExchange(addr)
if stateExchangeObject == nil { if stateExchangeObject == nil {
stateExchangeObject = self.createLendingExchangeObject(addr) stateExchangeObject = ls.createLendingExchangeObject(addr)
} }
return stateExchangeObject return stateExchangeObject
} }
// MarkStateLendObjectDirty adds the specified object to the dirty map to avoid costly // MarkStateLendObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones. // state object cache iteration to find a handful of modified ones.
func (self *LendingStateDB) MarkLendingExchangeObjectDirty(addr common.Hash) { func (ls *LendingStateDB) MarkLendingExchangeObjectDirty(addr common.Hash) {
self.lendingExchangeStatesDirty[addr] = struct{}{} ls.lendingExchangeStatesDirty[addr] = struct{}{}
} }
// createStateOrderListObject creates a new state object. If there is an existing tradeId with // createStateOrderListObject creates a new state object. If there is an existing tradeId with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *LendingStateDB) createLendingExchangeObject(hash common.Hash) (newobj *lendingExchangeState) { func (ls *LendingStateDB) createLendingExchangeObject(hash common.Hash) (newobj *lendingExchangeState) {
newobj = newStateExchanges(self, hash, lendingObject{}, self.MarkLendingExchangeObjectDirty) newobj = newStateExchanges(ls, hash, lendingObject{}, ls.MarkLendingExchangeObjectDirty)
newobj.setNonce(0) // sets the object to dirty newobj.setNonce(0) // sets the object to dirty
self.setLendingExchangeObject(newobj) ls.setLendingExchangeObject(newobj)
return newobj return newobj
} }
// Copy creates a deep, independent copy of the state. // Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy. // Snapshots of the copied state cannot be applied to the copy.
func (self *LendingStateDB) Copy() *LendingStateDB { func (ls *LendingStateDB) Copy() *LendingStateDB {
self.lock.Lock() ls.lock.Lock()
defer self.lock.Unlock() defer ls.lock.Unlock()
// Copy all the basic fields, initialize the memory ones // Copy all the basic fields, initialize the memory ones
state := &LendingStateDB{ state := &LendingStateDB{
db: self.db, db: ls.db,
trie: self.db.CopyTrie(self.trie), trie: ls.db.CopyTrie(ls.trie),
lendingExchangeStates: make(map[common.Hash]*lendingExchangeState, len(self.lendingExchangeStatesDirty)), lendingExchangeStates: make(map[common.Hash]*lendingExchangeState, len(ls.lendingExchangeStatesDirty)),
lendingExchangeStatesDirty: make(map[common.Hash]struct{}, len(self.lendingExchangeStatesDirty)), lendingExchangeStatesDirty: make(map[common.Hash]struct{}, len(ls.lendingExchangeStatesDirty)),
} }
// Copy the dirty states, logs, and preimages // Copy the dirty states, logs, and preimages
for addr := range self.lendingExchangeStatesDirty { for addr := range ls.lendingExchangeStatesDirty {
state.lendingExchangeStatesDirty[addr] = struct{}{} state.lendingExchangeStatesDirty[addr] = struct{}{}
} }
for addr, exchangeObject := range self.lendingExchangeStates { for addr, exchangeObject := range ls.lendingExchangeStates {
state.lendingExchangeStates[addr] = exchangeObject.deepCopy(state, state.MarkLendingExchangeObjectDirty) state.lendingExchangeStates[addr] = exchangeObject.deepCopy(state, state.MarkLendingExchangeObjectDirty)
} }
return state return state
} }
func (s *LendingStateDB) clearJournalAndRefund() { func (ls *LendingStateDB) clearJournalAndRefund() {
s.journal = nil ls.journal = nil
s.validRevisions = s.validRevisions[:0] ls.validRevisions = ls.validRevisions[:0]
} }
// Snapshot returns an identifier for the current revision of the state. // Snapshot returns an identifier for the current revision of the state.
func (self *LendingStateDB) Snapshot() int { func (ls *LendingStateDB) Snapshot() int {
id := self.nextRevisionId id := ls.nextRevisionId
self.nextRevisionId++ ls.nextRevisionId++
self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)}) ls.validRevisions = append(ls.validRevisions, revision{id, len(ls.journal)})
return id return id
} }
// RevertToSnapshot reverts all state changes made since the given revision. // RevertToSnapshot reverts all state changes made since the given revision.
func (self *LendingStateDB) RevertToSnapshot(revid int) { func (ls *LendingStateDB) RevertToSnapshot(revid int) {
// Find the snapshot in the stack of valid snapshots. // Find the snapshot in the stack of valid snapshots.
idx := sort.Search(len(self.validRevisions), func(i int) bool { idx := sort.Search(len(ls.validRevisions), func(i int) bool {
return self.validRevisions[i].id >= revid return ls.validRevisions[i].id >= revid
}) })
if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid { if idx == len(ls.validRevisions) || ls.validRevisions[idx].id != revid {
panic(fmt.Errorf("revision id %v cannot be reverted", revid)) panic(fmt.Errorf("revision id %v cannot be reverted", revid))
} }
snapshot := self.validRevisions[idx].journalIndex snapshot := ls.validRevisions[idx].journalIndex
// Replay the journal to undo changes. // Replay the journal to undo changes.
for i := len(self.journal) - 1; i >= snapshot; i-- { for i := len(ls.journal) - 1; i >= snapshot; i-- {
self.journal[i].undo(self) ls.journal[i].undo(ls)
} }
self.journal = self.journal[:snapshot] ls.journal = ls.journal[:snapshot]
// Remove invalidated snapshots from the stack. // Remove invalidated snapshots from the stack.
self.validRevisions = self.validRevisions[:idx] ls.validRevisions = ls.validRevisions[:idx]
} }
// Finalise finalises the state by removing the self destructed objects // Finalise finalises the state by removing the self destructed objects
// and clears the journal as well as the refunds. // and clears the journal as well as the refunds.
func (s *LendingStateDB) Finalise() { func (ls *LendingStateDB) Finalise() {
// Commit objects to the trie. // Commit objects to the trie.
for addr, stateObject := range s.lendingExchangeStates { for addr, stateObject := range ls.lendingExchangeStates {
if _, isDirty := s.lendingExchangeStatesDirty[addr]; isDirty { if _, isDirty := ls.lendingExchangeStatesDirty[addr]; isDirty {
// Write any storage changes in the state object to its storage trie. // Write any storage changes in the state object to its storage trie.
err := stateObject.updateInvestingRoot(s.db) err := stateObject.updateInvestingRoot(ls.db)
if err != nil { if err != nil {
log.Warn("Finalise updateInvestingRoot", "err", err, "addr", addr, "stateObject", *stateObject) log.Warn("Finalise updateInvestingRoot", "err", err, "addr", addr, "stateObject", *stateObject)
} }
stateObject.updateBorrowingRoot(s.db) stateObject.updateBorrowingRoot(ls.db)
stateObject.updateOrderRoot(s.db) stateObject.updateOrderRoot(ls.db)
stateObject.updateLendingTradeRoot(s.db) stateObject.updateLendingTradeRoot(ls.db)
stateObject.updateLiquidationTimeRoot(s.db) stateObject.updateLiquidationTimeRoot(ls.db)
// Update the object in the main tradeId trie. // Update the object in the main tradeId trie.
s.updateLendingExchange(stateObject) ls.updateLendingExchange(stateObject)
//delete(s.investingStatesDirty, addr) //delete(s.investingStatesDirty, addr)
} }
} }
s.clearJournalAndRefund() ls.clearJournalAndRefund()
} }
// IntermediateRoot computes the current root orderBook of the state trie. // IntermediateRoot computes the current root orderBook of the state trie.
// It is called in between transactions to get the root orderBook that // It is called in between transactions to get the root orderBook that
// goes into transaction receipts. // goes into transaction receipts.
func (s *LendingStateDB) IntermediateRoot() common.Hash { func (ls *LendingStateDB) IntermediateRoot() common.Hash {
s.Finalise() ls.Finalise()
return s.trie.Hash() return ls.trie.Hash()
} }
// Commit writes the state to the underlying in-memory trie database. // Commit writes the state to the underlying in-memory trie database.
func (s *LendingStateDB) Commit() (root common.Hash, err error) { func (ls *LendingStateDB) Commit() (root common.Hash, err error) {
defer s.clearJournalAndRefund() defer ls.clearJournalAndRefund()
// Commit objects to the trie. // Commit objects to the trie.
for addr, stateObject := range s.lendingExchangeStates { for addr, stateObject := range ls.lendingExchangeStates {
if _, isDirty := s.lendingExchangeStatesDirty[addr]; isDirty { if _, isDirty := ls.lendingExchangeStatesDirty[addr]; isDirty {
// Write any storage changes in the state object to its storage trie. // Write any storage changes in the state object to its storage trie.
if err := stateObject.CommitInvestingTrie(s.db); err != nil { if err := stateObject.CommitInvestingTrie(ls.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitBorrowingTrie(s.db); err != nil { if err := stateObject.CommitBorrowingTrie(ls.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitLendingItemTrie(s.db); err != nil { if err := stateObject.CommitLendingItemTrie(ls.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitLendingTradeTrie(s.db); err != nil { if err := stateObject.CommitLendingTradeTrie(ls.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
if err := stateObject.CommitLiquidationTimeTrie(s.db); err != nil { if err := stateObject.CommitLiquidationTimeTrie(ls.db); err != nil {
return EmptyHash, err return EmptyHash, err
} }
// Update the object in the main tradeId trie. // Update the object in the main tradeId trie.
s.updateLendingExchange(stateObject) ls.updateLendingExchange(stateObject)
delete(s.lendingExchangeStatesDirty, addr) delete(ls.lendingExchangeStatesDirty, addr)
} }
} }
// Write trie changes. // Write trie changes.
root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error { root, err = ls.trie.Commit(func(leaf []byte, parent common.Hash) error {
var exchange lendingObject var exchange lendingObject
if err := rlp.DecodeBytes(leaf, &exchange); err != nil { if err := rlp.DecodeBytes(leaf, &exchange); err != nil {
return nil return nil
} }
if exchange.InvestingRoot != EmptyRoot { if exchange.InvestingRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.InvestingRoot, parent) ls.db.TrieDB().Reference(exchange.InvestingRoot, parent)
} }
if exchange.BorrowingRoot != EmptyRoot { if exchange.BorrowingRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.BorrowingRoot, parent) ls.db.TrieDB().Reference(exchange.BorrowingRoot, parent)
} }
if exchange.LendingItemRoot != EmptyRoot { if exchange.LendingItemRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LendingItemRoot, parent) ls.db.TrieDB().Reference(exchange.LendingItemRoot, parent)
} }
if exchange.LendingTradeRoot != EmptyRoot { if exchange.LendingTradeRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LendingTradeRoot, parent) ls.db.TrieDB().Reference(exchange.LendingTradeRoot, parent)
} }
if exchange.LiquidationTimeRoot != EmptyRoot { if exchange.LiquidationTimeRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LiquidationTimeRoot, parent) ls.db.TrieDB().Reference(exchange.LiquidationTimeRoot, parent)
} }
return nil return nil
}) })
@ -602,38 +604,38 @@ func (s *LendingStateDB) Commit() (root common.Hash, err error) {
return root, err return root, err
} }
func (self *LendingStateDB) InsertLiquidationTime(lendingBook common.Hash, time *big.Int, tradeId uint64) { func (ls *LendingStateDB) InsertLiquidationTime(lendingBook common.Hash, time *big.Int, tradeId uint64) {
timeHash := common.BigToHash(time) timeHash := common.BigToHash(time)
lendingExchangeState := self.getLendingExchange(lendingBook) lendingExchangeState := ls.getLendingExchange(lendingBook)
if lendingExchangeState == nil { if lendingExchangeState == nil {
lendingExchangeState = self.createLendingExchangeObject(lendingBook) lendingExchangeState = ls.createLendingExchangeObject(lendingBook)
} }
liquidationTime := lendingExchangeState.getLiquidationTimeOrderList(self.db, timeHash) liquidationTime := lendingExchangeState.getLiquidationTimeOrderList(ls.db, timeHash)
if liquidationTime == nil { if liquidationTime == nil {
liquidationTime = lendingExchangeState.createLiquidationTime(self.db, timeHash) liquidationTime = lendingExchangeState.createLiquidationTime(ls.db, timeHash)
} }
liquidationTime.insertTradeId(self.db, common.Uint64ToHash(tradeId)) liquidationTime.insertTradeId(ls.db, common.Uint64ToHash(tradeId))
liquidationTime.AddVolume(One) liquidationTime.AddVolume(One)
} }
func (self *LendingStateDB) RemoveLiquidationTime(lendingBook common.Hash, tradeId uint64, time uint64) error { func (ls *LendingStateDB) RemoveLiquidationTime(lendingBook common.Hash, tradeId uint64, time uint64) error {
timeHash := common.Uint64ToHash(time) timeHash := common.Uint64ToHash(time)
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
lendingExchangeState := self.getLendingExchange(lendingBook) lendingExchangeState := ls.getLendingExchange(lendingBook)
if lendingExchangeState == nil { if lendingExchangeState == nil {
return fmt.Errorf("lending book not found : %s ", lendingBook.Hex()) return fmt.Errorf("lending book not found: %s", lendingBook.Hex())
} }
liquidationTime := lendingExchangeState.getLiquidationTimeOrderList(self.db, timeHash) liquidationTime := lendingExchangeState.getLiquidationTimeOrderList(ls.db, timeHash)
if liquidationTime == nil { if liquidationTime == nil {
return fmt.Errorf("liquidation time not found : %s , %d ", lendingBook.Hex(), time) return fmt.Errorf("not found liquidation time: %s , %d", lendingBook.Hex(), time)
} }
if !liquidationTime.Exist(self.db, tradeIdHash) { if !liquidationTime.Exist(ls.db, tradeIdHash) {
return fmt.Errorf("tradeId not exist : %s , %d , %d ", lendingBook.Hex(), time, tradeId) return fmt.Errorf("not exist tradeId: %s, %d, %d", lendingBook.Hex(), time, tradeId)
} }
liquidationTime.removeTradeId(self.db, tradeIdHash) liquidationTime.removeTradeId(ls.db, tradeIdHash)
liquidationTime.subVolume(One) liquidationTime.subVolume(One)
if liquidationTime.Volume().Sign() == 0 { if liquidationTime.Volume().Sign() == 0 {
err := lendingExchangeState.getLiquidationTimeTrie(self.db).TryDelete(timeHash[:]) err := lendingExchangeState.getLiquidationTimeTrie(ls.db).TryDelete(timeHash[:])
if err != nil { if err != nil {
log.Warn("RemoveLiquidationTime getLiquidationTimeTrie.TryDelete", "err", err, "timeHash[:]", timeHash[:]) log.Warn("RemoveLiquidationTime getLiquidationTimeTrie.TryDelete", "err", err, "timeHash[:]", timeHash[:])
} }
@ -641,33 +643,33 @@ func (self *LendingStateDB) RemoveLiquidationTime(lendingBook common.Hash, trade
return nil return nil
} }
func (self *LendingStateDB) GetLowestLiquidationTime(lendingBook common.Hash, time *big.Int) (*big.Int, []common.Hash) { func (ls *LendingStateDB) GetLowestLiquidationTime(lendingBook common.Hash, time *big.Int) (*big.Int, []common.Hash) {
liquidationData := []common.Hash{} liquidationData := []common.Hash{}
lendingExchangeState := self.getLendingExchange(lendingBook) lendingExchangeState := ls.getLendingExchange(lendingBook)
if lendingExchangeState == nil { if lendingExchangeState == nil {
return common.Big0, liquidationData return common.Big0, liquidationData
} }
lowestPriceHash, liquidationState := lendingExchangeState.getLowestLiquidationTime(self.db) lowestPriceHash, liquidationState := lendingExchangeState.getLowestLiquidationTime(ls.db)
lowestTime := new(big.Int).SetBytes(lowestPriceHash[:]) lowestTime := new(big.Int).SetBytes(lowestPriceHash[:])
if liquidationState != nil && lowestTime.Sign() > 0 && lowestTime.Cmp(time) <= 0 { if liquidationState != nil && lowestTime.Sign() > 0 && lowestTime.Cmp(time) <= 0 {
liquidationData = liquidationState.getAllTradeIds(self.db) liquidationData = liquidationState.getAllTradeIds(ls.db)
} }
return lowestTime, liquidationData return lowestTime, liquidationData
} }
func (self *LendingStateDB) CancelLendingTrade(orderBook common.Hash, tradeId uint64) error { func (ls *LendingStateDB) CancelLendingTrade(orderBook common.Hash, tradeId uint64) error {
tradeIdHash := common.Uint64ToHash(tradeId) tradeIdHash := common.Uint64ToHash(tradeId)
stateObject := self.GetOrNewLendingExchangeObject(orderBook) stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject == nil { if stateObject == nil {
return fmt.Errorf("Order book not found : %s ", orderBook.Hex()) return fmt.Errorf("not found order book: %s", orderBook.Hex())
} }
lendingTrade := stateObject.getLendingTrade(self.db, tradeIdHash) lendingTrade := stateObject.getLendingTrade(ls.db, tradeIdHash)
if lendingTrade == nil || lendingTrade.empty() { if lendingTrade == nil || lendingTrade.empty() {
return fmt.Errorf("lending trade empty order book : %s , trade id : %s , trade id hash : %s ", orderBook, tradeIdHash.Hex(), tradeIdHash.Hex()) return fmt.Errorf("lending trade empty order book: %s , trade id : %s , trade id hash : %s", orderBook, tradeIdHash.Hex(), tradeIdHash.Hex())
} }
self.journal = append(self.journal, cancelTrading{ ls.journal = append(ls.journal, cancelTrading{
orderBook: orderBook, orderBook: orderBook,
order: self.GetLendingTrade(orderBook, tradeIdHash), order: ls.GetLendingTrade(orderBook, tradeIdHash),
}) })
lendingTrade.SetAmount(Zero) lendingTrade.SetAmount(Zero)
return nil return nil

View file

@ -18,10 +18,11 @@ package lendingstate
import ( import (
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big" "math/big"
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
) )
func TestEchangeStates(t *testing.T) { func TestEchangeStates(t *testing.T) {
@ -225,9 +226,7 @@ func TestDumpStates(t *testing.T) {
orderBook := common.StringToHash("BTC/XDC") orderBook := common.StringToHash("BTC/XDC")
numberOrder := 20 numberOrder := 20
orderItems := []LendingItem{} orderItems := []LendingItem{}
relayers := []common.Hash{}
for i := 0; i < numberOrder; i++ { for i := 0; i < numberOrder; i++ {
relayers = append(relayers, common.BigToHash(big.NewInt(int64(i))))
id := new(big.Int).SetUint64(uint64(i) + 1) id := new(big.Int).SetUint64(uint64(i) + 1)
orderItems = append(orderItems, LendingItem{LendingId: id.Uint64(), Quantity: big.NewInt(int64(2*i + 1)), Interest: big.NewInt(1), Side: Investing, Signature: &Signature{V: 1, R: common.HexToHash("111111"), S: common.HexToHash("222222222222")}}) orderItems = append(orderItems, LendingItem{LendingId: id.Uint64(), Quantity: big.NewInt(int64(2*i + 1)), Interest: big.NewInt(1), Side: Investing, Signature: &Signature{V: 1, R: common.HexToHash("111111"), S: common.HexToHash("222222222222")}})
orderItems = append(orderItems, LendingItem{LendingId: id.Uint64(), Quantity: big.NewInt(int64(2*i + 1)), Interest: big.NewInt(1), Side: Borrowing, Signature: &Signature{V: 1, R: common.HexToHash("3333333333"), S: common.HexToHash("22222222222222222")}}) orderItems = append(orderItems, LendingItem{LendingId: id.Uint64(), Quantity: big.NewInt(int64(2*i + 1)), Interest: big.NewInt(1), Side: Borrowing, Signature: &Signature{V: 1, R: common.HexToHash("3333333333"), S: common.HexToHash("22222222222222222")}})

View file

@ -2,14 +2,14 @@ package lendingstate
import ( import (
"fmt" "fmt"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"math/big" "math/big"
"strconv" "strconv"
"time" "time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/globalsign/mgo/bson" "github.com/globalsign/mgo/bson"
"golang.org/x/crypto/sha3"
) )
const ( const (
@ -183,7 +183,7 @@ func (t *LendingTrade) SetBSON(raw bson.Raw) error {
} }
func (t *LendingTrade) ComputeHash() common.Hash { func (t *LendingTrade) ComputeHash() common.Hash {
sha := sha3.NewKeccak256() sha := sha3.NewLegacyKeccak256()
sha.Write(t.InvestingOrderHash.Bytes()) sha.Write(t.InvestingOrderHash.Bytes())
sha.Write(t.BorrowingOrderHash.Bytes()) sha.Write(t.BorrowingOrderHash.Bytes())
return common.BytesToHash(sha.Sum(nil)) return common.BytesToHash(sha.Sum(nil))

View file

@ -66,7 +66,7 @@ func (l *Lending) ApplyOrder(header *types.Header, coinbase common.Address, chai
switch order.Type { switch order.Type {
case lendingstate.TopUp: case lendingstate.TopUp:
err, reject, newLendingTrade := l.ProcessTopUp(lendingStateDB, statedb, tradingStateDb, order) reject, newLendingTrade, err := l.ProcessTopUp(lendingStateDB, statedb, tradingStateDb, order)
if err != nil || reject { if err != nil || reject {
rejects = append(rejects, order) rejects = append(rejects, order)
} }
@ -438,7 +438,7 @@ func (l *Lending) getLendQuantity(
} }
LendingTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, makerOrder.LendingToken) LendingTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, makerOrder.LendingToken)
if err != nil || LendingTokenDecimal.Sign() == 0 { if err != nil || LendingTokenDecimal.Sign() == 0 {
return lendingstate.Zero, lendingstate.Zero, false, nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", makerOrder.LendingToken.String(), err) return lendingstate.Zero, lendingstate.Zero, false, nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", makerOrder.LendingToken.String(), err)
} }
collateralToken := makerOrder.CollateralToken collateralToken := makerOrder.CollateralToken
if takerOrder.Side == lendingstate.Borrowing { if takerOrder.Side == lendingstate.Borrowing {
@ -446,7 +446,7 @@ func (l *Lending) getLendQuantity(
} }
collateralTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, collateralToken) collateralTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, collateralToken)
if err != nil || collateralTokenDecimal.Sign() == 0 { if err != nil || collateralTokenDecimal.Sign() == 0 {
return lendingstate.Zero, lendingstate.Zero, false, nil, fmt.Errorf("fail to get tokenDecimal. Token: %v . Err: %v", collateralToken.String(), err) return lendingstate.Zero, lendingstate.Zero, false, nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", collateralToken.String(), err)
} }
if takerOrder.Relayer == makerOrder.Relayer { if takerOrder.Relayer == makerOrder.Relayer {
if err := lendingstate.CheckRelayerFee(takerOrder.Relayer, new(big.Int).Mul(common.RelayerLendingFee, big.NewInt(2)), statedb); err != nil { if err := lendingstate.CheckRelayerFee(takerOrder.Relayer, new(big.Int).Mul(common.RelayerLendingFee, big.NewInt(2)), statedb); err != nil {
@ -582,7 +582,7 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *lendingsta
matchingFee = new(big.Int).Add(matchingFee, common.RelayerLendingFee) matchingFee = new(big.Int).Add(matchingFee, common.RelayerLendingFee)
if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) { if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) {
return fmt.Errorf("Echange owner empty , Taker: %v , maker : %v ", takerExOwner, makerExOwner) return fmt.Errorf("empty echange owner: taker: %v , maker : %v", takerExOwner, makerExOwner)
} }
mapBalances := map[common.Address]map[common.Address]*big.Int{} mapBalances := map[common.Address]map[common.Address]*big.Int{}
//Checking balance //Checking balance
@ -727,9 +727,10 @@ func (l *Lending) ProcessCancelOrder(header *types.Header, lendingStateDB *lendi
} }
} }
feeRate := lendingstate.GetFee(statedb, originOrder.Relayer) feeRate := lendingstate.GetFee(statedb, originOrder.Relayer)
tokenCancelFee, tokenPriceInXDC := common.Big0, common.Big0 var tokenCancelFee, tokenPriceInXDC *big.Int
if !chain.Config().IsTIPXDCXCancellationFee(header.Number) { if !chain.Config().IsTIPXDCXCancellationFee(header.Number) {
tokenCancelFee = getCancelFeeV1(collateralTokenDecimal, collateralPrice, feeRate, &originOrder) tokenCancelFee = getCancelFeeV1(collateralTokenDecimal, collateralPrice, feeRate, &originOrder)
tokenPriceInXDC = common.Big0
} else { } else {
tokenCancelFee, tokenPriceInXDC = l.getCancelFee(chain, statedb, tradingStateDb, &originOrder, feeRate) tokenCancelFee, tokenPriceInXDC = l.getCancelFee(chain, statedb, tradingStateDb, &originOrder, feeRate)
} }
@ -783,22 +784,22 @@ func (l *Lending) ProcessCancelOrder(header *types.Header, lendingStateDB *lendi
return nil, false return nil, false
} }
func (l *Lending) ProcessTopUp(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, order *lendingstate.LendingItem) (error, bool, *lendingstate.LendingTrade) { func (l *Lending) ProcessTopUp(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, order *lendingstate.LendingItem) (bool, *lendingstate.LendingTrade, error) {
lendingTradeId := common.Uint64ToHash(order.LendingTradeId) lendingTradeId := common.Uint64ToHash(order.LendingTradeId)
lendingBook := lendingstate.GetLendingOrderBookHash(order.LendingToken, order.Term) lendingBook := lendingstate.GetLendingOrderBookHash(order.LendingToken, order.Term)
lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId) lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId)
if lendingTrade == lendingstate.EmptyLendingTrade { if lendingTrade == lendingstate.EmptyLendingTrade {
return fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex()), true, nil return true, nil, fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex())
} }
if order.UserAddress != lendingTrade.Borrower { if order.UserAddress != lendingTrade.Borrower {
return fmt.Errorf("ProcessTopUp: invalid userAddress . UserAddress: %s . Borrower: %s", order.UserAddress.Hex(), lendingTrade.Borrower.Hex()), true, nil return true, nil, fmt.Errorf("ProcessTopUp: invalid userAddress . UserAddress: %s . Borrower: %s", order.UserAddress.Hex(), lendingTrade.Borrower.Hex())
} }
if order.Relayer != lendingTrade.BorrowingRelayer { if order.Relayer != lendingTrade.BorrowingRelayer {
return fmt.Errorf("ProcessTopUp: invalid relayerAddress . Got: %s . Expect: %s", order.Relayer.Hex(), lendingTrade.BorrowingRelayer.Hex()), true, nil return true, nil, fmt.Errorf("ProcessTopUp: invalid relayerAddress . Got: %s . Expect: %s", order.Relayer.Hex(), lendingTrade.BorrowingRelayer.Hex())
} }
if order.Quantity.Sign() <= 0 || lendingTrade.TradeId != lendingTradeId.Big().Uint64() { if order.Quantity.Sign() <= 0 || lendingTrade.TradeId != lendingTradeId.Big().Uint64() {
log.Debug("ProcessTopUp: invalid quantity", "Quantity", order.Quantity, "lendingTradeId", lendingTradeId.Hex()) log.Debug("ProcessTopUp: invalid quantity", "Quantity", order.Quantity, "lendingTradeId", lendingTradeId.Hex())
return nil, true, nil return true, nil, nil
} }
return l.ProcessTopUpLendingTrade(lendingStateDB, statedb, tradingStateDb, lendingTradeId, lendingBook, order.Quantity) return l.ProcessTopUpLendingTrade(lendingStateDB, statedb, tradingStateDb, lendingTradeId, lendingBook, order.Quantity)
} }
@ -927,7 +928,7 @@ func (l *Lending) LiquidationTrade(lendingStateDB *lendingstate.LendingStateDB,
// cancellation fee = 1/10 borrowing fee // cancellation fee = 1/10 borrowing fee
// deprecated after hardfork at TIPXDCXCancellationFee // deprecated after hardfork at TIPXDCXCancellationFee
func getCancelFeeV1(collateralTokenDecimal *big.Int, collateralPrice, borrowFee *big.Int, order *lendingstate.LendingItem) *big.Int { func getCancelFeeV1(collateralTokenDecimal *big.Int, collateralPrice, borrowFee *big.Int, order *lendingstate.LendingItem) *big.Int {
cancelFee := big.NewInt(0) var cancelFee *big.Int
if order.Side == lendingstate.Investing { if order.Side == lendingstate.Investing {
// cancel fee = quantityToLend*borrowFee/LendingCancelFee // cancel fee = quantityToLend*borrowFee/LendingCancelFee
cancelFee = new(big.Int).Mul(order.Quantity, borrowFee) cancelFee = new(big.Int).Mul(order.Quantity, borrowFee)
@ -947,7 +948,7 @@ func (l *Lending) getCancelFee(chain consensus.ChainContext, statedb *state.Stat
if feeRate == nil || feeRate.Sign() == 0 { if feeRate == nil || feeRate.Sign() == 0 {
return common.Big0, common.Big0 return common.Big0, common.Big0
} }
cancelFee, tokenPriceInXDC := common.Big0, common.Big0 var cancelFee, tokenPriceInXDC *big.Int
var err error var err error
if order.Side == lendingstate.Investing { if order.Side == lendingstate.Investing {
cancelFee, tokenPriceInXDC, err = l.XDCx.ConvertXDCToToken(chain, statedb, tradingStateDb, order.LendingToken, common.RelayerLendingCancelFee) cancelFee, tokenPriceInXDC, err = l.XDCx.ConvertXDCToToken(chain, statedb, tradingStateDb, order.LendingToken, common.RelayerLendingCancelFee)
@ -971,11 +972,11 @@ func (l *Lending) GetMediumTradePriceBeforeEpoch(chain consensus.ChainContext, s
if inversePrice != nil && inversePrice.Sign() > 0 { if inversePrice != nil && inversePrice.Sign() > 0 {
quoteTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, quoteToken) quoteTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, quoteToken)
if err != nil || quoteTokenDecimal.Sign() == 0 { if err != nil || quoteTokenDecimal.Sign() == 0 {
return nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", quoteToken.String(), err) return nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", quoteToken.String(), err)
} }
baseTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, baseToken) baseTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, baseToken)
if err != nil || baseTokenDecimal.Sign() == 0 { if err != nil || baseTokenDecimal.Sign() == 0 {
return nil, fmt.Errorf("Fail to get tokenDecimal. Token: %v . Err: %v", baseToken, err) return nil, fmt.Errorf("fail to get tokenDecimal: Token: %v . Err: %v", baseToken, err)
} }
price = new(big.Int).Mul(baseTokenDecimal, quoteTokenDecimal) price = new(big.Int).Mul(baseTokenDecimal, quoteTokenDecimal)
price = new(big.Int).Div(price, inversePrice) price = new(big.Int).Div(price, inversePrice)
@ -1098,7 +1099,7 @@ func (l *Lending) AutoTopUp(statedb *state.StateDB, tradingState *tradingstate.T
return nil, fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex()) return nil, fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex())
} }
if currentPrice.Cmp(lendingTrade.LiquidationPrice) >= 0 { if currentPrice.Cmp(lendingTrade.LiquidationPrice) >= 0 {
return nil, fmt.Errorf("CurrentPrice is still higher than or equal to LiquidationPrice. current price: %v , liquidation price : %v ", currentPrice, lendingTrade.LiquidationPrice) return nil, fmt.Errorf("currentPrice is still higher than or equal to LiquidationPrice. current price: %v , liquidation price : %v ", currentPrice, lendingTrade.LiquidationPrice)
} }
// newLiquidationPrice = currentPrice * 90% // newLiquidationPrice = currentPrice * 90%
newLiquidationPrice := new(big.Int).Mul(currentPrice, common.RateTopUp) newLiquidationPrice := new(big.Int).Mul(currentPrice, common.RateTopUp)
@ -1112,23 +1113,23 @@ func (l *Lending) AutoTopUp(statedb *state.StateDB, tradingState *tradingstate.T
if tokenBalance.Cmp(requiredDepositAmount) < 0 { if tokenBalance.Cmp(requiredDepositAmount) < 0 {
return nil, fmt.Errorf("not enough balance to AutoTopUp. requiredDepositAmount: %v . tokenBalance: %v . Token: %s", requiredDepositAmount, tokenBalance, lendingTrade.CollateralToken.Hex()) return nil, fmt.Errorf("not enough balance to AutoTopUp. requiredDepositAmount: %v . tokenBalance: %v . Token: %s", requiredDepositAmount, tokenBalance, lendingTrade.CollateralToken.Hex())
} }
err, _, newTrade := l.ProcessTopUpLendingTrade(lendingState, statedb, tradingState, lendingTradeId, lendingBook, requiredDepositAmount) _, newTrade, err := l.ProcessTopUpLendingTrade(lendingState, statedb, tradingState, lendingTradeId, lendingBook, requiredDepositAmount)
return newTrade, err return newTrade, err
} }
func (l *Lending) ProcessTopUpLendingTrade(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, lendingTradeId common.Hash, lendingBook common.Hash, quantity *big.Int) (error, bool, *lendingstate.LendingTrade) { func (l *Lending) ProcessTopUpLendingTrade(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, lendingTradeId common.Hash, lendingBook common.Hash, quantity *big.Int) (bool, *lendingstate.LendingTrade, error) {
lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId) lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId)
if lendingTrade == lendingstate.EmptyLendingTrade { if lendingTrade == lendingstate.EmptyLendingTrade {
return fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex()), true, nil return true, nil, fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex())
} }
tokenBalance := lendingstate.GetTokenBalance(lendingTrade.Borrower, lendingTrade.CollateralToken, statedb) tokenBalance := lendingstate.GetTokenBalance(lendingTrade.Borrower, lendingTrade.CollateralToken, statedb)
if tokenBalance.Cmp(quantity) < 0 { if tokenBalance.Cmp(quantity) < 0 {
log.Debug("not enough balance deposit", "Quantity", quantity, "tokenBalance", tokenBalance) log.Debug("not enough balance deposit", "Quantity", quantity, "tokenBalance", tokenBalance)
return fmt.Errorf("not enough balance deposit. lendingTradeId: %v , Quantity : %v , tokenBalance : %v", lendingTradeId.Hex(), quantity, tokenBalance), true, nil return true, nil, fmt.Errorf("not enough balance deposit. lendingTradeId: %v , Quantity : %v , tokenBalance : %v", lendingTradeId.Hex(), quantity, tokenBalance)
} }
err := tradingStateDb.RemoveLiquidationPrice(tradingstate.GetTradingOrderBookHash(lendingTrade.CollateralToken, lendingTrade.LendingToken), lendingTrade.LiquidationPrice, lendingBook, lendingTrade.TradeId) err := tradingStateDb.RemoveLiquidationPrice(tradingstate.GetTradingOrderBookHash(lendingTrade.CollateralToken, lendingTrade.LendingToken), lendingTrade.LiquidationPrice, lendingBook, lendingTrade.TradeId)
if err != nil { if err != nil {
return err, true, nil return true, nil, err
} }
err = lendingstate.SubTokenBalance(lendingTrade.Borrower, quantity, lendingTrade.CollateralToken, statedb) err = lendingstate.SubTokenBalance(lendingTrade.Borrower, quantity, lendingTrade.CollateralToken, statedb)
if err != nil { if err != nil {
@ -1149,7 +1150,7 @@ func (l *Lending) ProcessTopUpLendingTrade(lendingStateDB *lendingstate.LendingS
newLendingTrade.LiquidationPrice = newLiquidationPrice newLendingTrade.LiquidationPrice = newLiquidationPrice
newLendingTrade.CollateralLockedAmount = newLockedAmount newLendingTrade.CollateralLockedAmount = newLockedAmount
log.Debug("ProcessTopUp successfully", "price", newLiquidationPrice, "lockAmount", newLockedAmount) log.Debug("ProcessTopUp successfully", "price", newLiquidationPrice, "lockAmount", newLockedAmount)
return nil, false, &newLendingTrade return false, &newLendingTrade, nil
} }
func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus.ChainContext, lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingstateDB *tradingstate.TradingStateDB, lendingBook common.Hash, lendingTradeId uint64) (trade *lendingstate.LendingTrade, err error) { func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus.ChainContext, lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingstateDB *tradingstate.TradingStateDB, lendingBook common.Hash, lendingTradeId uint64) (trade *lendingstate.LendingTrade, err error) {
@ -1165,7 +1166,7 @@ func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus
if tokenBalance.Cmp(paymentBalance) < 0 { if tokenBalance.Cmp(paymentBalance) < 0 {
if lendingTrade.LiquidationTime > time { if lendingTrade.LiquidationTime > time {
return nil, fmt.Errorf("Not enough balance need : %s , have : %s ", paymentBalance, tokenBalance) return nil, fmt.Errorf("not enough balance need : %s , have : %s", paymentBalance, tokenBalance)
} }
newLendingTrade := &lendingstate.LendingTrade{} newLendingTrade := &lendingstate.LendingTrade{}
var err error var err error
@ -1235,14 +1236,14 @@ func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus
return &lendingTrade, nil return &lendingTrade, nil
} }
func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, lendingBook common.Hash, lendingTradeId common.Hash, newLiquidationPrice *big.Int) (error, bool, *lendingstate.LendingTrade) { func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.LendingStateDB, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, lendingBook common.Hash, lendingTradeId common.Hash, newLiquidationPrice *big.Int) (bool, *lendingstate.LendingTrade, error) {
log.Debug("ProcessRecallLendingTrade", "lendingTradeId", lendingTradeId.Hex(), "lendingBook", lendingBook.Hex(), "newLiquidationPrice", newLiquidationPrice) log.Debug("ProcessRecallLendingTrade", "lendingTradeId", lendingTradeId.Hex(), "lendingBook", lendingBook.Hex(), "newLiquidationPrice", newLiquidationPrice)
lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId) lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId)
if lendingTrade == lendingstate.EmptyLendingTrade { if lendingTrade == lendingstate.EmptyLendingTrade {
return fmt.Errorf("process recall for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex()), true, nil return true, nil, fmt.Errorf("process recall for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex())
} }
if newLiquidationPrice.Cmp(lendingTrade.LiquidationPrice) <= 0 { if newLiquidationPrice.Cmp(lendingTrade.LiquidationPrice) <= 0 {
return fmt.Errorf("New liquidation price must higher than old liquidation price. current liquidation price: %v , new liquidation price : %v ", lendingTrade.LiquidationPrice, newLiquidationPrice), true, nil return true, nil, fmt.Errorf("New liquidation price must higher than old liquidation price. current liquidation price: %v , new liquidation price : %v ", lendingTrade.LiquidationPrice, newLiquidationPrice)
} }
newLockedAmount := new(big.Int).Mul(lendingTrade.CollateralLockedAmount, lendingTrade.LiquidationPrice) newLockedAmount := new(big.Int).Mul(lendingTrade.CollateralLockedAmount, lendingTrade.LiquidationPrice)
newLockedAmount = new(big.Int).Div(newLockedAmount, newLiquidationPrice) newLockedAmount = new(big.Int).Div(newLockedAmount, newLiquidationPrice)
@ -1250,7 +1251,7 @@ func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.Lending
log.Debug("ProcessRecallLendingTrade", "newLockedAmount", newLockedAmount, "recallAmount", recallAmount, "oldLiquidationPrice", lendingTrade.LiquidationPrice, "newLiquidationPrice", newLiquidationPrice) log.Debug("ProcessRecallLendingTrade", "newLockedAmount", newLockedAmount, "recallAmount", recallAmount, "oldLiquidationPrice", lendingTrade.LiquidationPrice, "newLiquidationPrice", newLiquidationPrice)
err := tradingStateDb.RemoveLiquidationPrice(tradingstate.GetTradingOrderBookHash(lendingTrade.CollateralToken, lendingTrade.LendingToken), lendingTrade.LiquidationPrice, lendingBook, lendingTrade.TradeId) err := tradingStateDb.RemoveLiquidationPrice(tradingstate.GetTradingOrderBookHash(lendingTrade.CollateralToken, lendingTrade.LendingToken), lendingTrade.LiquidationPrice, lendingBook, lendingTrade.TradeId)
if err != nil { if err != nil {
return err, true, nil return true, nil, err
} }
err = lendingstate.AddTokenBalance(lendingTrade.Borrower, recallAmount, lendingTrade.CollateralToken, statedb) err = lendingstate.AddTokenBalance(lendingTrade.Borrower, recallAmount, lendingTrade.CollateralToken, statedb)
if err != nil { if err != nil {
@ -1268,5 +1269,5 @@ func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.Lending
newLendingTrade.LiquidationPrice = newLiquidationPrice newLendingTrade.LiquidationPrice = newLiquidationPrice
newLendingTrade.CollateralLockedAmount = newLockedAmount newLendingTrade.CollateralLockedAmount = newLockedAmount
log.Debug("ProcessRecall", "price", newLiquidationPrice, "lockAmount", newLockedAmount, "recall amount", recallAmount) log.Debug("ProcessRecall", "price", newLiquidationPrice, "lockAmount", newLockedAmount, "recall amount", recallAmount)
return nil, false, &newLendingTrade return false, &newLendingTrade, nil
} }

View file

@ -19,6 +19,7 @@ package abi
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"log" "log"
"math/big" "math/big"
@ -713,3 +714,34 @@ func TestABI_MethodById(t *testing.T) {
} }
} }
func TestUnpackRevert(t *testing.T) {
t.Parallel()
var cases = []struct {
input string
expect string
expectErr error
}{
{"", "", errors.New("invalid data for unpacking")},
{"08c379a1", "", errors.New("invalid data for unpacking")},
{"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil},
}
for index, c := range cases {
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
got, err := UnpackRevert(common.Hex2Bytes(c.input))
if c.expectErr != nil {
if err == nil {
t.Fatalf("Expected non-nil error")
}
if err.Error() != c.expectErr.Error() {
t.Fatalf("Expected error mismatch, want %v, got %v", c.expectErr, err)
}
return
}
if c.expect != got {
t.Fatalf("Output mismatch, want %v, got %v", c.expect, got)
}
})
}
}

View file

@ -20,7 +20,6 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
"io" "io"
"io/ioutil"
"math/big" "math/big"
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
@ -80,7 +79,7 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
// NewTransactorWithChainID is a utility method to easily create a transaction signer from // NewTransactorWithChainID is a utility method to easily create a transaction signer from
// an encrypted json key stream and the associated passphrase. // an encrypted json key stream and the associated passphrase.
func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.Int) (*TransactOpts, error) { func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.Int) (*TransactOpts, error) {
json, err := ioutil.ReadAll(keyin) json, err := io.ReadAll(keyin)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -32,12 +32,12 @@ var (
// have any code associated with it (i.e. suicided). // have any code associated with it (i.e. suicided).
ErrNoCode = errors.New("no contract code at given address") ErrNoCode = errors.New("no contract code at given address")
// This error is raised when attempting to perform a pending state action // ErrNoPendingState is raised when attempting to perform a pending state action
// on a backend that doesn't implement PendingContractCaller. // on a backend that doesn't implement PendingContractCaller.
ErrNoPendingState = errors.New("backend does not support pending state") ErrNoPendingState = errors.New("backend does not support pending state")
// This error is returned by WaitDeployed if contract creation leaves an // ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves
// empty contract behind. // an empty contract behind.
ErrNoCodeAfterDeploy = errors.New("no contract code after deployment") ErrNoCodeAfterDeploy = errors.New("no contract code after deployment")
) )
@ -47,7 +47,8 @@ type ContractCaller interface {
// CodeAt returns the code of the given account. This is needed to differentiate // CodeAt returns the code of the given account. This is needed to differentiate
// between contract internal errors and the local chain being out of sync. // between contract internal errors and the local chain being out of sync.
CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error)
// ContractCall executes an Ethereum contract call with the specified data as the
// CallContract executes an Ethereum contract call with the specified data as the
// input. // input.
CallContract(ctx context.Context, call XDPoSChain.CallMsg, blockNumber *big.Int) ([]byte, error) CallContract(ctx context.Context, call XDPoSChain.CallMsg, blockNumber *big.Int) ([]byte, error)
} }
@ -58,6 +59,7 @@ type ContractCaller interface {
type PendingContractCaller interface { type PendingContractCaller interface {
// PendingCodeAt returns the code of the given account in the pending state. // PendingCodeAt returns the code of the given account in the pending state.
PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error)
// PendingCallContract executes an Ethereum contract call against the pending state. // PendingCallContract executes an Ethereum contract call against the pending state.
PendingCallContract(ctx context.Context, call XDPoSChain.CallMsg) ([]byte, error) PendingCallContract(ctx context.Context, call XDPoSChain.CallMsg) ([]byte, error)
} }
@ -67,19 +69,31 @@ type PendingContractCaller interface {
// used when the user does not provide some needed values, but rather leaves it up // used when the user does not provide some needed values, but rather leaves it up
// to the transactor to decide. // to the transactor to decide.
type ContractTransactor interface { type ContractTransactor interface {
// HeaderByNumber returns a block header from the current canonical chain. If
// number is nil, the latest known header is returned.
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
// PendingCodeAt returns the code of the given account in the pending state. // PendingCodeAt returns the code of the given account in the pending state.
PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error)
// PendingNonceAt retrieves the current pending nonce associated with an account. // PendingNonceAt retrieves the current pending nonce associated with an account.
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely // SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction. // execution of a transaction.
SuggestGasPrice(ctx context.Context) (*big.Int, error) SuggestGasPrice(ctx context.Context) (*big.Int, error)
// SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow
// a timely execution of a transaction.
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
// EstimateGas tries to estimate the gas needed to execute a specific // EstimateGas tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain. // transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as other // There is no guarantee that this is the true gas limit requirement as other
// transactions may be added or removed by miners, but it should provide a basis // transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default. // for setting a reasonable default.
EstimateGas(ctx context.Context, call XDPoSChain.CallMsg) (gas uint64, err error) EstimateGas(ctx context.Context, call XDPoSChain.CallMsg) (gas uint64, err error)
// SendTransaction injects the transaction into the pending pool for execution. // SendTransaction injects the transaction into the pending pool for execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error SendTransaction(ctx context.Context, tx *types.Transaction) error
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCx" "github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCxlending" "github.com/XinFinOrg/XDPoSChain/XDCxlending"
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/keystore" "github.com/XinFinOrg/XDPoSChain/accounts/keystore"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
@ -42,6 +43,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/eth/filters" "github.com/XinFinOrg/XDPoSChain/eth/filters"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
@ -53,7 +55,6 @@ import (
var _ bind.ContractBackend = (*SimulatedBackend)(nil) var _ bind.ContractBackend = (*SimulatedBackend)(nil)
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block") var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
var errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction")
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in // SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
// the background. Its main purpose is to allow easily testing contract bindings. // the background. Its main purpose is to allow easily testing contract bindings.
@ -86,10 +87,10 @@ func SimulateWalletAddressAndSignFn() (common.Address, func(account accounts.Acc
pass := "" // not used but required by API pass := "" // not used but required by API
a1, err := ks.NewAccount(pass) a1, err := ks.NewAccount(pass)
if err != nil { if err != nil {
return common.Address{}, nil, fmt.Errorf(err.Error()) return common.Address{}, nil, err
} }
if err := ks.Unlock(a1, ""); err != nil { if err := ks.Unlock(a1, ""); err != nil {
return a1.Address, nil, fmt.Errorf(err.Error()) return a1.Address, nil, err
} }
return a1.Address, ks.SignHash, nil return a1.Address, ks.SignHash, nil
} }
@ -101,7 +102,7 @@ func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64, chainConfi
GasLimit: gasLimit, // need this big, support initial smart contract GasLimit: gasLimit, // need this big, support initial smart contract
Config: chainConfig, Config: chainConfig,
Alloc: alloc, Alloc: alloc,
ExtraData: append(make([]byte, 32), make([]byte, 65)...), ExtraData: append(make([]byte, 32), make([]byte, crypto.SignatureLength)...),
} }
genesis.MustCommit(database) genesis.MustCommit(database)
consensus := XDPoS.NewFaker(database, chainConfig) consensus := XDPoS.NewFaker(database, chainConfig)
@ -160,6 +161,12 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
return backend return backend
} }
// Close terminates the underlying blockchain's update loop.
func (b *SimulatedBackend) Close() error {
b.blockchain.Stop()
return nil
}
// Commit imports all the pending transactions as a single block and starts a // Commit imports all the pending transactions as a single block and starts a
// fresh new state. // fresh new state.
func (b *SimulatedBackend) Commit() { func (b *SimulatedBackend) Commit() {
@ -256,6 +263,19 @@ func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common
return receipt, nil return receipt, nil
} }
// HeaderByNumber returns a block header from the current canonical chain. If number is
// nil, the latest known header is returned.
func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, block *big.Int) (*types.Header, error) {
b.mu.Lock()
defer b.mu.Unlock()
if block == nil || block.Cmp(b.pendingBlock.Number()) == 0 {
return b.blockchain.CurrentHeader(), nil
}
return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
}
// PendingCodeAt returns the code associated with an account in the pending state. // PendingCodeAt returns the code associated with an account in the pending state.
func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
b.mu.Lock() b.mu.Lock()
@ -276,8 +296,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call XDPoSChain.Cal
if err != nil { if err != nil {
return nil, err return nil, err
} }
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state) res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
return rval, err if err != nil {
return nil, err
}
return res.Return(), nil
} }
// PendingCallContract executes a contract call on the pending state. // PendingCallContract executes a contract call on the pending state.
@ -286,8 +309,11 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call XDPoSCh
defer b.mu.Unlock() defer b.mu.Unlock()
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
return rval, err if err != nil {
return nil, err
}
return res.Return(), nil
} }
// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving // PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
@ -300,8 +326,17 @@ func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Ad
} }
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated // SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
// chain doens't have miners, we just return a gas price of 1 for any call. // chain doesn't have miners, we just return a gas price of 1 for any call.
func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
if b.pendingBlock.Header().BaseFee != nil {
return b.pendingBlock.Header().BaseFee, nil
}
return big.NewInt(1), nil
}
// SuggestGasTipCap implements ContractTransactor.SuggestGasTipCap. Since the simulated
// chain doesn't have miners, we just return a gas tip of 1 for any call.
func (b *SimulatedBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
return big.NewInt(1), nil return big.NewInt(1), nil
} }
@ -325,22 +360,33 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
cap = hi cap = hi
// Create a helper to check if a gas allowance results in an executable transaction // Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool { executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
call.Gas = gas call.Gas = gas
snapshot := b.pendingState.Snapshot() snapshot := b.pendingState.Snapshot()
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
b.pendingState.RevertToSnapshot(snapshot) b.pendingState.RevertToSnapshot(snapshot)
if err != nil || failed { if err != nil {
return false if err == core.ErrIntrinsicGas {
return true, nil, nil // Special case, raise gas limit
}
return true, nil, err // Bail out
} }
return true return res.Failed(), res, nil
} }
// Execute the binary search and hone in on an executable gas limit // Execute the binary search and hone in on an executable gas limit
for lo+1 < hi { for lo+1 < hi {
mid := (hi + lo) / 2 mid := (hi + lo) / 2
if !executable(mid) { failed, _, err := executable(mid)
// If the error is not nil(consensus error), it means the provided message
// call or transaction will never be accepted no matter how much gas it is
// assigned. Return the error directly, don't struggle any more
if err != nil {
return 0, err
}
if failed {
lo = mid lo = mid
} else { } else {
hi = mid hi = mid
@ -348,8 +394,25 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
} }
// Reject the transaction as invalid if it still fails at the highest allowance // Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap { if hi == cap {
if !executable(hi) { failed, result, err := executable(hi)
return 0, errGasEstimationFailed if err != nil {
return 0, err
}
if failed {
if result != nil && result.Err != vm.ErrOutOfGas {
errMsg := fmt.Sprintf("always failing transaction (%v)", result.Err)
if len(result.Revert()) > 0 {
ret, err := abi.UnpackRevert(result.Revert())
if err != nil {
errMsg += fmt.Sprintf(" (%#x)", result.Revert())
} else {
errMsg += fmt.Sprintf(" (%s)", ret)
}
}
return 0, errors.New(errMsg)
}
// Otherwise, the specified gas cap is too low
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
} }
} }
return hi, nil return hi, nil
@ -357,11 +420,39 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
// callContract implements common code between normal and pending contract calls. // callContract implements common code between normal and pending contract calls.
// state is modified during execution, make sure to copy it if necessary. // state is modified during execution, make sure to copy it if necessary.
func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.CallMsg, block *types.Block, statedb *state.StateDB) (ret []byte, usedGas uint64, failed bool, err error) { func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.CallMsg, block *types.Block, statedb *state.StateDB) (*core.ExecutionResult, error) {
// Ensure message is initialized properly. // Gas prices post 1559 need to be initialized
if call.GasPrice == nil { if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
call.GasPrice = big.NewInt(1) return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} }
head := b.blockchain.CurrentHeader()
if !b.blockchain.Config().IsEIP1559(head.Number) {
// If there's no basefee, then it must be a non-1559 execution
if call.GasPrice == nil {
call.GasPrice = new(big.Int)
}
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
} else {
// A basefee is provided, necessitating 1559-type execution
if call.GasPrice != nil {
// User specified the legacy gas field, convert to 1559 gas typing
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
} else {
// User specified 1559 gas feilds (or none), use those
if call.GasFeeCap == nil {
call.GasFeeCap = new(big.Int)
}
if call.GasTipCap == nil {
call.GasTipCap = new(big.Int)
}
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
call.GasPrice = new(big.Int)
if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 {
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, head.BaseFee), call.GasFeeCap)
}
}
}
// Ensure message is initialized properly.
if call.Gas == 0 { if call.Gas == 0 {
call.Gas = 50000000 call.Gas = 50000000
} }
@ -379,14 +470,16 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
msg.CallMsg.BalanceTokenFee = value msg.CallMsg.BalanceTokenFee = value
} }
} }
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
txContext := core.NewEVMTxContext(msg)
evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, nil, b.config, vm.Config{}) vmenv := vm.NewEVM(evmContext, txContext, statedb, nil, b.config, vm.Config{NoBaseFee: true})
gaspool := new(core.GasPool).AddGas(math.MaxUint64) gaspool := new(core.GasPool).AddGas(math.MaxUint64)
owner := common.Address{} owner := common.Address{}
ret, usedGas, failed, err, _ = core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner) res, err, _ := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
return return res, err
} }
// SendTransaction updates the pending block to include the given transaction. // SendTransaction updates the pending block to include the given transaction.
@ -520,9 +613,11 @@ type callMsg struct {
func (m callMsg) From() common.Address { return m.CallMsg.From } func (m callMsg) From() common.Address { return m.CallMsg.From }
func (m callMsg) Nonce() uint64 { return 0 } func (m callMsg) Nonce() uint64 { return 0 }
func (m callMsg) CheckNonce() bool { return false } func (m callMsg) IsFake() bool { return true }
func (m callMsg) To() *common.Address { return m.CallMsg.To } func (m callMsg) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas } func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value } func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data } func (m callMsg) Data() []byte { return m.CallMsg.Data }
@ -552,7 +647,11 @@ func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*t
} }
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil number := rawdb.ReadHeaderNumber(fb.db, hash)
if number == nil {
return nil, nil
}
return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil
} }
func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {

View file

@ -0,0 +1,154 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package backends
import (
"context"
"errors"
"math/big"
"strings"
"testing"
"github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
)
func TestSimulatedBackend_EstimateGas(t *testing.T) {
/*
pragma solidity ^0.6.4;
contract GasEstimation {
function PureRevert() public { revert(); }
function Revert() public { revert("revert reason");}
function OOG() public { for (uint i = 0; ; i++) {}}
function Assert() public { assert(false);}
function Valid() public {}
}*/
const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
const contractBin = "0x60806040523480156100115760006000fd5b50610017565b61016e806100266000396000f3fe60806040523480156100115760006000fd5b506004361061005c5760003560e01c806350f6fe3414610062578063aa8b1d301461006c578063b9b046f914610076578063d8b9839114610080578063e09fface1461008a5761005c565b60006000fd5b61006a610094565b005b6100746100ad565b005b61007e6100b5565b005b6100886100c2565b005b610092610135565b005b6000600090505b5b808060010191505061009b565b505b565b60006000fd5b565b600015156100bf57fe5b5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f72657665727420726561736f6e0000000000000000000000000000000000000081526020015060200191505060405180910390fd5b565b5b56fea2646970667358221220345bbcbb1a5ecf22b53a78eaebf95f8ee0eceff6d10d4b9643495084d2ec934a64736f6c63430006040033"
key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey)
opts := bind.NewKeyedTransactor(key)
sim := NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether)}}, 10000000, &params.ChainConfig{
ConstantinopleBlock: big.NewInt(0),
XDPoS: &params.XDPoSConfig{
Epoch: 900,
SkipV1Validation: true,
V2: &params.V2{
SwitchBlock: big.NewInt(900),
CurrentConfig: params.UnitTestV2Configs[0],
},
},
})
defer sim.Close()
parsed, _ := abi.JSON(strings.NewReader(contractAbi))
contractAddr, _, _, _ := bind.DeployContract(opts, parsed, common.FromHex(contractBin), sim)
sim.Commit()
var cases = []struct {
name string
message XDPoSChain.CallMsg
expect uint64
expectError error
}{
{"plain transfer(valid)", XDPoSChain.CallMsg{
From: addr,
To: &addr,
Gas: 0,
GasPrice: big.NewInt(0),
Value: big.NewInt(1),
Data: nil,
}, params.TxGas, nil},
{"plain transfer(invalid)", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 0,
GasPrice: big.NewInt(0),
Value: big.NewInt(1),
Data: nil,
}, 0, errors.New("always failing transaction (execution reverted)")},
{"Revert", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 0,
GasPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("d8b98391"),
}, 0, errors.New("always failing transaction (execution reverted) (revert reason)")},
{"PureRevert", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 0,
GasPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("aa8b1d30"),
}, 0, errors.New("always failing transaction (execution reverted)")},
{"OOG", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 100000,
GasPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("50f6fe34"),
}, 0, errors.New("gas required exceeds allowance (100000)")},
{"Assert", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 100000,
GasPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("b9b046f9"),
}, 0, errors.New("always failing transaction (invalid opcode: INVALID)")},
{"Valid", XDPoSChain.CallMsg{
From: addr,
To: &contractAddr,
Gas: 100000,
GasPrice: big.NewInt(0),
Value: nil,
Data: common.Hex2Bytes("e09fface"),
}, 21483, nil},
}
for _, c := range cases {
got, err := sim.EstimateGas(context.Background(), c.message)
if c.expectError != nil {
if err == nil {
t.Fatalf("Expect error, got nil")
}
if c.expectError.Error() != err.Error() {
t.Fatalf("Expect error, want %v, got %v", c.expectError, err)
}
continue
}
if got != c.expect {
t.Fatalf("Gas estimation mismatch, want %d, got %d", c.expect, got)
}
}
}

View file

@ -53,11 +53,15 @@ type TransactOpts struct {
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
Signer SignerFn // Method to use for signing the transaction (mandatory) Signer SignerFn // Method to use for signing the transaction (mandatory)
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
NoSend bool // Do all transact steps but do not send the transaction
} }
// FilterOpts is the collection of options to fine tune filtering for events // FilterOpts is the collection of options to fine tune filtering for events
@ -184,57 +188,158 @@ func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error)
return c.transact(opts, &c.address, nil) return c.transact(opts, &c.address, nil)
} }
// transact executes an actual transaction invocation, first deriving any missing func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) {
// authorization fields, and then scheduling the transaction for execution. // Normalize value
func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
var err error
// Ensure a valid value field and resolve the account nonce
value := opts.Value value := opts.Value
if value == nil { if value == nil {
value = new(big.Int) value = new(big.Int)
} }
var nonce uint64 // Estimate TipCap
if opts.Nonce == nil { gasTipCap := opts.GasTipCap
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) if gasTipCap == nil {
tip, err := c.transactor.SuggestGasTipCap(ensureContext(opts.Context))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) return nil, err
} }
} else { gasTipCap = tip
nonce = opts.Nonce.Uint64()
} }
// Figure out the gas allowance and gas price values // Estimate FeeCap
gasFeeCap := opts.GasFeeCap
if gasFeeCap == nil {
gasFeeCap = new(big.Int).Add(
gasTipCap,
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
)
}
if gasFeeCap.Cmp(gasTipCap) < 0 {
return nil, fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap)
}
// Estimate GasLimit
gasLimit := opts.GasLimit
if opts.GasLimit == 0 {
var err error
gasLimit, err = c.estimateGasLimit(opts, contract, input, nil, gasTipCap, gasFeeCap, value)
if err != nil {
return nil, err
}
}
// create the transaction
nonce, err := c.getNonce(opts)
if err != nil {
return nil, err
}
baseTx := &types.DynamicFeeTx{
To: contract,
Nonce: nonce,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Gas: gasLimit,
Value: value,
Data: input,
}
return types.NewTx(baseTx), nil
}
func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasFeeCap != nil || opts.GasTipCap != nil {
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but EIP-1559 is not active yet")
}
// Normalize value
value := opts.Value
if value == nil {
value = new(big.Int)
}
// Estimate GasPrice
gasPrice := opts.GasPrice gasPrice := opts.GasPrice
if gasPrice == nil { if gasPrice == nil {
gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context)) price, err := c.transactor.SuggestGasPrice(ensureContext(opts.Context))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to suggest gas price: %v", err) return nil, err
} }
gasPrice = price
} }
// Estimate GasLimit
gasLimit := opts.GasLimit gasLimit := opts.GasLimit
if gasLimit == 0 { if opts.GasLimit == 0 {
// Gas estimation cannot succeed without code for method invocations var err error
if contract != nil { gasLimit, err = c.estimateGasLimit(opts, contract, input, gasPrice, nil, nil, value)
if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
return nil, err
} else if len(code) == 0 {
return nil, ErrNoCode
}
}
// If the contract surely has code (or code is not needed), estimate the transaction
msg := XDPoSChain.CallMsg{From: opts.From, To: contract, Value: value, Data: input}
gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to estimate gas needed: %v", err) return nil, err
} }
} }
// Create the transaction, sign it and schedule it for execution // create the transaction
var rawTx *types.Transaction nonce, err := c.getNonce(opts)
if contract == nil { if err != nil {
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) return nil, err
} else {
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input)
} }
baseTx := &types.LegacyTx{
To: contract,
Nonce: nonce,
GasPrice: gasPrice,
Gas: gasLimit,
Value: value,
Data: input,
}
return types.NewTx(baseTx), nil
}
func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int) (uint64, error) {
if contract != nil {
// Gas estimation cannot succeed without code for method invocations.
if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
return 0, err
} else if len(code) == 0 {
return 0, ErrNoCode
}
}
msg := XDPoSChain.CallMsg{
From: opts.From,
To: contract,
GasPrice: gasPrice,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Value: value,
Data: input,
}
return c.transactor.EstimateGas(ensureContext(opts.Context), msg)
}
func (c *BoundContract) getNonce(opts *TransactOpts) (uint64, error) {
if opts.Nonce == nil {
return c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
} else {
return opts.Nonce.Uint64(), nil
}
}
// transact executes an actual transaction invocation, first deriving any missing
// authorization fields, and then scheduling the transaction for execution.
func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasPrice != nil && (opts.GasFeeCap != nil || opts.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
// Create the transaction
var (
rawTx *types.Transaction
err error
)
if opts.GasPrice != nil {
rawTx, err = c.createLegacyTx(opts, contract, input)
} else {
// Only query for basefee if gasPrice not specified
if head, errHead := c.transactor.HeaderByNumber(ensureContext(opts.Context), nil); errHead != nil {
return nil, errHead
} else if head.BaseFee != nil {
rawTx, err = c.createDynamicTx(opts, contract, input, head)
} else {
// Chain is not London ready -> use legacy transaction
rawTx, err = c.createLegacyTx(opts, contract, input)
}
}
if err != nil {
return nil, err
}
// Sign the transaction and schedule it for execution
if opts.Signer == nil { if opts.Signer == nil {
return nil, errors.New("no signer to authorize the transaction with") return nil, errors.New("no signer to authorize the transaction with")
} }
@ -242,6 +347,9 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if err != nil { if err != nil {
return nil, err return nil, err
} }
if opts.NoSend {
return signedTx, nil
}
if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil {
return nil, err return nil, err
} }
@ -280,7 +388,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
sub, err := event.NewSubscription(func(quit <-chan struct{}) error { sub := event.NewSubscription(func(quit <-chan struct{}) error {
for _, log := range buff { for _, log := range buff {
select { select {
case logs <- log: case logs <- log:
@ -289,11 +397,8 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
} }
} }
return nil return nil
}), nil })
if err != nil {
return nil, nil, err
}
return logs, sub, nil return logs, sub, nil
} }

View file

@ -0,0 +1,177 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bind_test
import (
"context"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/stretchr/testify/assert"
)
func mockSign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { return tx, nil }
type mockTransactor struct {
baseFee *big.Int
gasTipCap *big.Int
gasPrice *big.Int
suggestGasTipCapCalled bool
suggestGasPriceCalled bool
}
func (mt *mockTransactor) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
return &types.Header{BaseFee: mt.baseFee}, nil
}
func (mt *mockTransactor) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
return []byte{1}, nil
}
func (mt *mockTransactor) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
return 0, nil
}
func (mt *mockTransactor) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
mt.suggestGasPriceCalled = true
return mt.gasPrice, nil
}
func (mt *mockTransactor) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
mt.suggestGasTipCapCalled = true
return mt.gasTipCap, nil
}
func (mt *mockTransactor) EstimateGas(ctx context.Context, call XDPoSChain.CallMsg) (gas uint64, err error) {
return 0, nil
}
func (mt *mockTransactor) SendTransaction(ctx context.Context, tx *types.Transaction) error {
return nil
}
type mockCaller struct {
codeAtBlockNumber *big.Int
callContractBlockNumber *big.Int
pendingCodeAtCalled bool
pendingCallContractCalled bool
}
func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
mc.codeAtBlockNumber = blockNumber
return []byte{1, 2, 3}, nil
}
func (mc *mockCaller) CallContract(ctx context.Context, call XDPoSChain.CallMsg, blockNumber *big.Int) ([]byte, error) {
mc.callContractBlockNumber = blockNumber
return nil, nil
}
func (mc *mockCaller) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
mc.pendingCodeAtCalled = true
return nil, nil
}
func (mc *mockCaller) PendingCallContract(ctx context.Context, call XDPoSChain.CallMsg) ([]byte, error) {
mc.pendingCallContractCalled = true
return nil, nil
}
func TestPassingBlockNumber(t *testing.T) {
mc := &mockCaller{}
bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{
Methods: map[string]abi.Method{
"something": {
Name: "something",
Outputs: abi.Arguments{},
},
},
}, mc, nil, nil)
bc.Call(&bind.CallOpts{}, nil, "something")
bc.Call(&bind.CallOpts{}, nil, "something")
if mc.callContractBlockNumber != nil {
t.Fatalf("CallContract() was passed a block number when it should not have been")
}
if mc.codeAtBlockNumber != nil {
t.Fatalf("CodeAt() was passed a block number when it should not have been")
}
bc.Call(&bind.CallOpts{Pending: true}, nil, "something")
if !mc.pendingCallContractCalled {
t.Fatalf("CallContract() was not passed the block number")
}
if !mc.pendingCodeAtCalled {
t.Fatalf("CodeAt() was not passed the block number")
}
}
func TestTransactGasFee(t *testing.T) {
assert := assert.New(t)
// GasTipCap and GasFeeCap
// When opts.GasTipCap and opts.GasFeeCap are nil
mt := &mockTransactor{baseFee: big.NewInt(100), gasTipCap: big.NewInt(5)}
bc := bind.NewBoundContract(common.Address{}, abi.ABI{}, nil, mt, nil)
opts := &bind.TransactOpts{Signer: mockSign}
tx, err := bc.Transact(opts, "")
assert.Nil(err)
assert.Equal(big.NewInt(5), tx.GasTipCap())
assert.Equal(big.NewInt(205), tx.GasFeeCap())
assert.Nil(opts.GasTipCap)
assert.Nil(opts.GasFeeCap)
assert.True(mt.suggestGasTipCapCalled)
// Second call to Transact should use latest suggested GasTipCap
mt.gasTipCap = big.NewInt(6)
mt.suggestGasTipCapCalled = false
tx, err = bc.Transact(opts, "")
assert.Nil(err)
assert.Equal(big.NewInt(6), tx.GasTipCap())
assert.Equal(big.NewInt(206), tx.GasFeeCap())
assert.True(mt.suggestGasTipCapCalled)
// GasPrice
// When opts.GasPrice is nil
mt = &mockTransactor{gasPrice: big.NewInt(5)}
bc = bind.NewBoundContract(common.Address{}, abi.ABI{}, nil, mt, nil)
opts = &bind.TransactOpts{Signer: mockSign}
tx, err = bc.Transact(opts, "")
assert.Nil(err)
assert.Equal(big.NewInt(5), tx.GasPrice())
assert.Nil(opts.GasPrice)
assert.True(mt.suggestGasPriceCalled)
// Second call to Transact should use latest suggested GasPrice
mt.gasPrice = big.NewInt(6)
mt.suggestGasPriceCalled = false
tx, err = bc.Transact(opts, "")
assert.Nil(err)
assert.Equal(big.NewInt(6), tx.GasPrice())
assert.True(mt.suggestGasPriceCalled)
}

View file

@ -37,8 +37,6 @@ type Lang int
const ( const (
LangGo Lang = iota LangGo Lang = iota
LangJava
LangObjC
) )
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
@ -119,7 +117,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
} }
contracts[types[i]] = &tmplContract{ contracts[types[i]] = &tmplContract{
Type: capitalise(types[i]), Type: capitalise(types[i]),
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1), InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""),
InputBin: strings.TrimSpace(bytecodes[i]), InputBin: strings.TrimSpace(bytecodes[i]),
Constructor: evmABI.Constructor, Constructor: evmABI.Constructor,
Calls: calls, Calls: calls,
@ -160,15 +158,15 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
// bindType is a set of type binders that convert Solidity types to some supported // bindType is a set of type binders that convert Solidity types to some supported
// programming language types. // programming language types.
var bindType = map[Lang]func(kind abi.Type) string{ var bindType = map[Lang]func(kind abi.Type) string{
LangGo: bindTypeGo, LangGo: bindTypeGo,
LangJava: bindTypeJava,
} }
// Helper function for the binding generators. // Helper function for the binding generators.
// It reads the unmatched characters after the inner type-match, // It reads the unmatched characters after the inner type-match,
// (since the inner type is a prefix of the total type declaration), //
// looks for valid arrays (possibly a dynamic one) wrapping the inner type, // (since the inner type is a prefix of the total type declaration),
// and returns the sizes of these arrays. // looks for valid arrays (possibly a dynamic one) wrapping the inner type,
// and returns the sizes of these arrays.
// //
// Returned array sizes are in the same order as solidity signatures; inner array size first. // Returned array sizes are in the same order as solidity signatures; inner array size first.
// Array sizes may also be "", indicating a dynamic array. // Array sizes may also be "", indicating a dynamic array.
@ -244,15 +242,6 @@ func arrayBindingJava(inner string, arraySizes []string) string {
return inner + strings.Repeat("[]", len(arraySizes)) return inner + strings.Repeat("[]", len(arraySizes))
} }
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeJava(kind abi.Type) string {
stringKind := kind.String()
innerLen, innerMapping := bindUnnestedTypeJava(stringKind)
return arrayBindingJava(wrapArray(stringKind, innerLen, innerMapping))
}
// The inner function of bindTypeJava, this finds the inner type of stringKind. // The inner function of bindTypeJava, this finds the inner type of stringKind.
// (Or just the type itself if it is not an array or slice) // (Or just the type itself if it is not an array or slice)
// The length of the matched part is returned, with the the translated type. // The length of the matched part is returned, with the the translated type.
@ -311,8 +300,7 @@ func bindUnnestedTypeJava(stringKind string) (int, string) {
// bindTopicType is a set of type binders that convert Solidity types to some // bindTopicType is a set of type binders that convert Solidity types to some
// supported programming language topic types. // supported programming language topic types.
var bindTopicType = map[Lang]func(kind abi.Type) string{ var bindTopicType = map[Lang]func(kind abi.Type) string{
LangGo: bindTopicTypeGo, LangGo: bindTopicTypeGo,
LangJava: bindTopicTypeJava,
} }
// bindTypeGo converts a Solidity topic type to a Go one. It is almost the same // bindTypeGo converts a Solidity topic type to a Go one. It is almost the same
@ -325,64 +313,16 @@ func bindTopicTypeGo(kind abi.Type) string {
return bound return bound
} }
// bindTypeGo converts a Solidity topic type to a Java one. It is almost the same
// funcionality as for simple types, but dynamic types get converted to hashes.
func bindTopicTypeJava(kind abi.Type) string {
bound := bindTypeJava(kind)
if bound == "String" || bound == "Bytes" {
bound = "Hash"
}
return bound
}
// namedType is a set of functions that transform language specific types to // namedType is a set of functions that transform language specific types to
// named versions that my be used inside method names. // named versions that my be used inside method names.
var namedType = map[Lang]func(string, abi.Type) string{ var namedType = map[Lang]func(string, abi.Type) string{
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") }, LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
LangJava: namedTypeJava,
}
// namedTypeJava converts some primitive data types to named variants that can
// be used as parts of method names.
func namedTypeJava(javaKind string, solKind abi.Type) string {
switch javaKind {
case "byte[]":
return "Binary"
case "byte[][]":
return "Binaries"
case "string":
return "String"
case "string[]":
return "Strings"
case "boolean":
return "Bool"
case "boolean[]":
return "Bools"
case "BigInt[]":
return "BigInts"
default:
parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
if len(parts) != 4 {
return javaKind
}
switch parts[2] {
case "8", "16", "32", "64":
if parts[3] == "" {
return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2]))
}
return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2]))
default:
return javaKind
}
}
} }
// methodNormalizer is a name transformer that modifies Solidity method names to // methodNormalizer is a name transformer that modifies Solidity method names to
// conform to target language naming concentions. // conform to target language naming concentions.
var methodNormalizer = map[Lang]func(string) string{ var methodNormalizer = map[Lang]func(string) string{
LangGo: capitalise, LangGo: capitalise,
LangJava: decapitalise,
} }
// capitalise makes a camel-case string which starts with an upper case character. // capitalise makes a camel-case string which starts with an upper case character.

View file

@ -229,7 +229,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy an interaction tester contract and call a transaction on it // Deploy an interaction tester contract and call a transaction on it
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") _, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@ -270,7 +270,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, getter, err := DeployGetter(auth, sim) _, _, getter, err := DeployGetter(auth, sim)
@ -302,7 +302,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, tupler, err := DeployTupler(auth, sim) _, _, tupler, err := DeployTupler(auth, sim)
@ -344,7 +344,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a slice tester contract and execute a n array call on it // Deploy a slice tester contract and execute a n array call on it
_, _, slicer, err := DeploySlicer(auth, sim) _, _, slicer, err := DeploySlicer(auth, sim)
@ -378,7 +378,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a default method invoker contract and execute its default method // Deploy a default method invoker contract and execute its default method
_, _, defaulter, err := DeployDefaulter(auth, sim) _, _, defaulter, err := DeployDefaulter(auth, sim)
@ -447,7 +447,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a funky gas pattern contract // Deploy a funky gas pattern contract
_, _, limiter, err := DeployFunkyGasPattern(auth, sim) _, _, limiter, err := DeployFunkyGasPattern(auth, sim)
@ -482,7 +482,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a sender tester contract and execute a structured call on it // Deploy a sender tester contract and execute a structured call on it
_, _, callfrom, err := DeployCallFrom(auth, sim) _, _, callfrom, err := DeployCallFrom(auth, sim)
@ -542,7 +542,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a underscorer tester contract and execute a structured call on it // Deploy a underscorer tester contract and execute a structured call on it
_, _, underscorer, err := DeployUnderscorer(auth, sim) _, _, underscorer, err := DeployUnderscorer(auth, sim)
@ -612,7 +612,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy an eventer contract // Deploy an eventer contract
_, _, eventer, err := DeployEventer(auth, sim) _, _, eventer, err := DeployEventer(auth, sim)
@ -761,7 +761,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
//deploy the test contract //deploy the test contract
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim) _, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
@ -821,7 +821,7 @@ func TestBindings(t *testing.T) {
} }
t.Log("Using config", params.TestXDPoSMockChainConfig) t.Log("Using config", params.TestXDPoSMockChainConfig)
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845) // Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}") linkTestCode := "package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}"
linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil) linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil)
if err != nil { if err != nil {
t.Fatalf("failed check for goimports symlink bug: %v", err) t.Fatalf("failed check for goimports symlink bug: %v", err)

View file

@ -52,8 +52,7 @@ type tmplEvent struct {
// tmplSource is language to template mapping containing all the supported // tmplSource is language to template mapping containing all the supported
// programming languages the package can generate to. // programming languages the package can generate to.
var tmplSource = map[Lang]string{ var tmplSource = map[Lang]string{
LangGo: tmplSourceGo, LangGo: tmplSourceGo,
LangJava: tmplSourceJava,
} }
// tmplSourceGo is the Go source template use to generate the contract binding // tmplSourceGo is the Go source template use to generate the contract binding
@ -418,105 +417,3 @@ package {{.Package}}
{{end}} {{end}}
{{end}} {{end}}
` `
// tmplSourceJava is the Java source template use to generate the contract binding
// based on.
const tmplSourceJava = `
// This file is an automatically generated Java binding. Do not modify as any
// change will likely be lost upon the next re-generation!
package {{.Package}};
import org.ethereum.geth.*;
import org.ethereum.geth.internal.*;
{{range $contract := .Contracts}}
public class {{.Type}} {
// ABI is the input ABI used to generate the binding from.
public final static String ABI = "{{.InputABI}}";
{{if .InputBin}}
// BYTECODE is the compiled bytecode used for deploying new contracts.
public final static byte[] BYTECODE = "{{.InputBin}}".getBytes();
// deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}});
{{range $index, $element := .Constructor.Inputs}}
args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
{{end}}
return new {{.Type}}(Geth.deployContract(auth, ABI, BYTECODE, client, args));
}
// Internal constructor used by contract deployment.
private {{.Type}}(BoundContract deployment) {
this.Address = deployment.getAddress();
this.Deployer = deployment.getDeployer();
this.Contract = deployment;
}
{{end}}
// Ethereum address where this contract is located at.
public final Address Address;
// Ethereum transaction in which this contract was deployed (if known!).
public final Transaction Deployer;
// Contract instance bound to a blockchain address.
private final BoundContract Contract;
// Creates a new instance of {{.Type}}, bound to a specific deployed contract.
public {{.Type}}(Address address, EthereumClient client) throws Exception {
this(Geth.bindContract(address, ABI, client));
}
{{range .Calls}}
{{if gt (len .Normalized.Outputs) 1}}
// {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}.
public class {{capitalise .Normalized.Name}}Results {
{{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}};
{{end}}
}
{{end}}
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
//
// Solidity: {{.Original.String}}
public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
{{end}}
Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}});
{{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type) .Type}}(); results.set({{$index}}, result{{$index}});
{{end}}
if (opts == null) {
opts = Geth.newCallOpts();
}
this.Contract.call(opts, results, "{{.Original.Name}}", args);
{{if gt (len .Normalized.Outputs) 1}}
{{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results();
{{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type) .Type}}();
{{end}}
return result;
{{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type) .Type}}();{{end}}
{{end}}
}
{{end}}
{{range .Transacts}}
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
//
// Solidity: {{.Original.String}}
public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
{{end}}
return this.Contract.transact(opts, "{{.Original.Name}}" , args);
}
{{end}}
}
{{end}}
`

View file

@ -53,15 +53,20 @@ var waitDeployedTests = map[string]struct {
} }
func TestWaitDeployed(t *testing.T) { func TestWaitDeployed(t *testing.T) {
config := *params.TestXDPoSMockChainConfig
config.Eip1559Block = big.NewInt(0)
for name, test := range waitDeployedTests { for name, test := range waitDeployedTests {
backend := backends.NewXDCSimulatedBackend( backend := backends.NewXDCSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(100000000000000000)},
}, 10000000, params.TestXDPoSMockChainConfig, }, 10000000, &config,
) )
// Create the transaction. // Create the transaction
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
// Wait for it to get mined in the background. // Wait for it to get mined in the background.

View file

@ -102,7 +102,7 @@ func TestTypeRegexp(t *testing.T) {
t.Errorf("type %q: failed to parse type string: %v", tt.blob, err) t.Errorf("type %q: failed to parse type string: %v", tt.blob, err)
} }
if !reflect.DeepEqual(typ, tt.kind) { if !reflect.DeepEqual(typ, tt.kind) {
t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(tt.kind))) t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s", tt.blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(tt.kind)))
} }
} }
} }

View file

@ -201,11 +201,11 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
if keyProtected.Version != version { if keyProtected.Version != version {
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) return nil, nil, fmt.Errorf("not supported Version: %v", keyProtected.Version)
} }
if keyProtected.Crypto.Cipher != "aes-128-ctr" { if keyProtected.Crypto.Cipher != "aes-128-ctr" {
return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher) return nil, nil, fmt.Errorf("not supported Cipher: %v", keyProtected.Crypto.Cipher)
} }
keyId = uuid.Parse(keyProtected.Id) keyId = uuid.Parse(keyProtected.Id)
@ -293,13 +293,13 @@ func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
c := ensureInt(cryptoJSON.KDFParams["c"]) c := ensureInt(cryptoJSON.KDFParams["c"])
prf := cryptoJSON.KDFParams["prf"].(string) prf := cryptoJSON.KDFParams["prf"].(string)
if prf != "hmac-sha256" { if prf != "hmac-sha256" {
return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) return nil, fmt.Errorf("unsupported PBKDF2 PRF: %s", prf)
} }
key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
return key, nil return key, nil
} }
return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) return nil, fmt.Errorf("unsupported KDF: %s", cryptoJSON.KDF)
} }
// TODO: can we do without this when unmarshalling dynamic JSON? // TODO: can we do without this when unmarshalling dynamic JSON?

View file

@ -211,7 +211,7 @@ func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
} }
privHex := hex.EncodeToString(privBytes) privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex { if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex)) t.Fatal(fmt.Errorf("decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
} }
} }
@ -222,7 +222,7 @@ func testDecryptV1(test KeyStoreTestV1, t *testing.T) {
} }
privHex := hex.EncodeToString(privBytes) privHex := hex.EncodeToString(privBytes)
if test.Priv != privHex { if test.Priv != privHex {
t.Fatal(fmt.Errorf("Decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex)) t.Fatal(fmt.Errorf("decrypted bytes not equal to test, expected %v have %v", test.Priv, privHex))
} }
} }

View file

@ -64,7 +64,7 @@ func (u URL) String() string {
func (u URL) TerminalString() string { func (u URL) TerminalString() string {
url := u.String() url := u.String()
if len(url) > 32 { if len(url) > 32 {
return url[:31] + "" return url[:31] + ".."
} }
return url return url
} }
@ -76,10 +76,9 @@ func (u URL) MarshalJSON() ([]byte, error) {
// Cmp compares x and y and returns: // Cmp compares x and y and returns:
// //
// -1 if x < y // -1 if x < y
// 0 if x == y // 0 if x == y
// +1 if x > y // +1 if x > y
//
func (u URL) Cmp(url URL) int { func (u URL) Cmp(url URL) int {
if u.Scheme == url.Scheme { if u.Scheme == url.Scheme {
return strings.Compare(u.Path, url.Path) return strings.Compare(u.Path, url.Path)

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
) )
@ -164,7 +165,7 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
} }
// Ensure the wallet is capable of signing the given transaction // Ensure the wallet is capable of signing the given transaction
if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 { if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2]) return common.Address{}, nil, fmt.Errorf("ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
} }
// All infos gathered and metadata checks out, request signing // All infos gathered and metadata checks out, request signing
return w.ledgerSign(path, tx, chainID) return w.ledgerSign(path, tx, chainID)
@ -175,18 +176,18 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
// //
// The version retrieval protocol is defined as follows: // The version retrieval protocol is defined as follows:
// //
// CLA | INS | P1 | P2 | Lc | Le // CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+----+--- // ----+-----+----+----+----+---
// E0 | 06 | 00 | 00 | 00 | 04 // E0 | 06 | 00 | 00 | 00 | 04
// //
// With no input data, and the output data being: // With no input data, and the output data being:
// //
// Description | Length // Description | Length
// ---------------------------------------------------+-------- // ---------------------------------------------------+--------
// Flags 01: arbitrary data signature enabled by user | 1 byte // Flags 01: arbitrary data signature enabled by user | 1 byte
// Application major version | 1 byte // Application major version | 1 byte
// Application minor version | 1 byte // Application minor version | 1 byte
// Application patch version | 1 byte // Application patch version | 1 byte
func (w *ledgerDriver) ledgerVersion() ([3]byte, error) { func (w *ledgerDriver) ledgerVersion() ([3]byte, error) {
// Send the request and wait for the response // Send the request and wait for the response
reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil) reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil)
@ -207,32 +208,32 @@ func (w *ledgerDriver) ledgerVersion() ([3]byte, error) {
// //
// The address derivation protocol is defined as follows: // The address derivation protocol is defined as follows:
// //
// CLA | INS | P1 | P2 | Lc | Le // CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+--- // ----+-----+----+----+-----+---
// E0 | 02 | 00 return address // E0 | 02 | 00 return address
// 01 display address and confirm before returning // 01 display address and confirm before returning
// | 00: do not return the chain code // | 00: do not return the chain code
// | 01: return the chain code // | 01: return the chain code
// | var | 00 // | var | 00
// //
// Where the input data is: // Where the input data is:
// //
// Description | Length // Description | Length
// -------------------------------------------------+-------- // -------------------------------------------------+--------
// Number of BIP 32 derivations to perform (max 10) | 1 byte // Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes // First derivation index (big endian) | 4 bytes
// ... | 4 bytes // ... | 4 bytes
// Last derivation index (big endian) | 4 bytes // Last derivation index (big endian) | 4 bytes
// //
// And the output data is: // And the output data is:
// //
// Description | Length // Description | Length
// ------------------------+------------------- // ------------------------+-------------------
// Public Key length | 1 byte // Public Key length | 1 byte
// Uncompressed Public Key | arbitrary // Uncompressed Public Key | arbitrary
// Ethereum address length | 1 byte // Ethereum address length | 1 byte
// Ethereum address | 40 bytes hex ascii // Ethereum address | 40 bytes hex ascii
// Chain code if requested | 32 bytes // Chain code if requested | 32 bytes
func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) { func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) {
// Flatten the derivation path into the Ledger request // Flatten the derivation path into the Ledger request
path := make([]byte, 1+4*len(derivationPath)) path := make([]byte, 1+4*len(derivationPath))
@ -268,35 +269,35 @@ func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, er
// //
// The transaction signing protocol is defined as follows: // The transaction signing protocol is defined as follows:
// //
// CLA | INS | P1 | P2 | Lc | Le // CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+--- // ----+-----+----+----+-----+---
// E0 | 04 | 00: first transaction data block // E0 | 04 | 00: first transaction data block
// 80: subsequent transaction data block // 80: subsequent transaction data block
// | 00 | variable | variable // | 00 | variable | variable
// //
// Where the input for the first transaction block (first 255 bytes) is: // Where the input for the first transaction block (first 255 bytes) is:
// //
// Description | Length // Description | Length
// -------------------------------------------------+---------- // -------------------------------------------------+----------
// Number of BIP 32 derivations to perform (max 10) | 1 byte // Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes // First derivation index (big endian) | 4 bytes
// ... | 4 bytes // ... | 4 bytes
// Last derivation index (big endian) | 4 bytes // Last derivation index (big endian) | 4 bytes
// RLP transaction chunk | arbitrary // RLP transaction chunk | arbitrary
// //
// And the input for subsequent transaction blocks (first 255 bytes) are: // And the input for subsequent transaction blocks (first 255 bytes) are:
// //
// Description | Length // Description | Length
// ----------------------+---------- // ----------------------+----------
// RLP transaction chunk | arbitrary // RLP transaction chunk | arbitrary
// //
// And the output data is: // And the output data is:
// //
// Description | Length // Description | Length
// ------------+--------- // ------------+---------
// signature V | 1 byte // signature V | 1 byte
// signature R | 32 bytes // signature R | 32 bytes
// signature S | 32 bytes // signature S | 32 bytes
func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) { func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
// Flatten the derivation path into the Ledger request // Flatten the derivation path into the Ledger request
path := make([]byte, 1+4*len(derivationPath)) path := make([]byte, 1+4*len(derivationPath))
@ -341,7 +342,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
op = ledgerP1ContTransactionData op = ledgerP1ContTransactionData
} }
// Extract the Ethereum signature and do a sanity validation // Extract the Ethereum signature and do a sanity validation
if len(reply) != 65 { if len(reply) != crypto.SignatureLength {
return common.Address{}, nil, errors.New("reply lacks signature") return common.Address{}, nil, errors.New("reply lacks signature")
} }
signature := append(reply[1:], reply[0]) signature := append(reply[1:], reply[0])
@ -352,7 +353,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
signer = new(types.HomesteadSigner) signer = new(types.HomesteadSigner)
} else { } else {
signer = types.NewEIP155Signer(chainID) signer = types.NewEIP155Signer(chainID)
signature[64] = signature[64] - byte(chainID.Uint64()*2+35) signature[crypto.RecoveryIDOffset] = signature[crypto.RecoveryIDOffset] - byte(chainID.Uint64()*2+35)
} }
signed, err := tx.WithSignature(signer, signature) signed, err := tx.WithSignature(signer, signature)
if err != nil { if err != nil {
@ -370,12 +371,12 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
// //
// The common transport header is defined as follows: // The common transport header is defined as follows:
// //
// Description | Length // Description | Length
// --------------------------------------+---------- // --------------------------------------+----------
// Communication channel ID (big endian) | 2 bytes // Communication channel ID (big endian) | 2 bytes
// Command tag | 1 byte // Command tag | 1 byte
// Packet sequence index (big endian) | 2 bytes // Packet sequence index (big endian) | 2 bytes
// Payload | arbitrary // Payload | arbitrary
// //
// The Communication channel ID allows commands multiplexing over the same // The Communication channel ID allows commands multiplexing over the same
// physical link. It is not used for the time being, and should be set to 0101 // physical link. It is not used for the time being, and should be set to 0101
@ -389,15 +390,15 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
// //
// APDU Command payloads are encoded as follows: // APDU Command payloads are encoded as follows:
// //
// Description | Length // Description | Length
// ----------------------------------- // -----------------------------------
// APDU length (big endian) | 2 bytes // APDU length (big endian) | 2 bytes
// APDU CLA | 1 byte // APDU CLA | 1 byte
// APDU INS | 1 byte // APDU INS | 1 byte
// APDU P1 | 1 byte // APDU P1 | 1 byte
// APDU P2 | 1 byte // APDU P2 | 1 byte
// APDU length | 1 byte // APDU length | 1 byte
// Optional APDU data | arbitrary // Optional APDU data | arbitrary
func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) { func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
// Construct the message payload, possibly split into multiple chunks // Construct the message payload, possibly split into multiple chunks
apdu := make([]byte, 2, 7+len(data)) apdu := make([]byte, 2, 7+len(data))

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil" "github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
@ -222,7 +223,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
} else { } else {
// Trezor backend does not support typed transactions yet. // Trezor backend does not support typed transactions yet.
signer = types.NewEIP155Signer(chainID) signer = types.NewEIP155Signer(chainID)
signature[64] = signature[64] - byte(chainID.Uint64()*2+35) signature[crypto.RecoveryIDOffset] = signature[crypto.RecoveryIDOffset] - byte(chainID.Uint64()*2+35)
} }
// Inject the final signature into the transaction and sanity check the sender // Inject the final signature into the transaction and sanity check the sender

View file

@ -150,29 +150,29 @@ func NewTreePool(hasher BaseHasher, segmentCount, capacity int) *TreePool {
} }
// Drain drains the pool uptil it has no more than n resources // Drain drains the pool uptil it has no more than n resources
func (self *TreePool) Drain(n int) { func (tp *TreePool) Drain(n int) {
self.lock.Lock() tp.lock.Lock()
defer self.lock.Unlock() defer tp.lock.Unlock()
for len(self.c) > n { for len(tp.c) > n {
<-self.c <-tp.c
self.count-- tp.count--
} }
} }
// Reserve is blocking until it returns an available Tree // Reserve is blocking until it returns an available Tree
// it reuses free Trees or creates a new one if size is not reached // it reuses free Trees or creates a new one if size is not reached
func (self *TreePool) Reserve() *Tree { func (tp *TreePool) Reserve() *Tree {
self.lock.Lock() tp.lock.Lock()
defer self.lock.Unlock() defer tp.lock.Unlock()
var t *Tree var t *Tree
if self.count == self.Capacity { if tp.count == tp.Capacity {
return <-self.c return <-tp.c
} }
select { select {
case t = <-self.c: case t = <-tp.c:
default: default:
t = NewTree(self.hasher, self.SegmentSize, self.SegmentCount) t = NewTree(tp.hasher, tp.SegmentSize, tp.SegmentCount)
self.count++ tp.count++
} }
return t return t
} }
@ -180,8 +180,8 @@ func (self *TreePool) Reserve() *Tree {
// Release gives back a Tree to the pool. // Release gives back a Tree to the pool.
// This Tree is guaranteed to be in reusable state // This Tree is guaranteed to be in reusable state
// does not need locking // does not need locking
func (self *TreePool) Release(t *Tree) { func (tp *TreePool) Release(t *Tree) {
self.c <- t // can never fail but... tp.c <- t // can never fail but...
} }
// Tree is a reusable control structure representing a BMT // Tree is a reusable control structure representing a BMT
@ -193,17 +193,14 @@ type Tree struct {
} }
// Draw draws the BMT (badly) // Draw draws the BMT (badly)
func (self *Tree) Draw(hash []byte, d int) string { func (t *Tree) Draw(hash []byte, d int) string {
var left, right []string var left, right []string
var anc []*Node var anc []*Node
for i, n := range self.leaves { for _, n := range t.leaves {
left = append(left, fmt.Sprintf("%v", hashstr(n.left))) left = append(left, fmt.Sprintf("%v", hashstr(n.left)))
if i%2 == 0 {
anc = append(anc, n.parent)
}
right = append(right, fmt.Sprintf("%v", hashstr(n.right))) right = append(right, fmt.Sprintf("%v", hashstr(n.right)))
} }
anc = self.leaves anc = t.leaves
var hashes [][]string var hashes [][]string
for l := 0; len(anc) > 0; l++ { for l := 0; len(anc) > 0; l++ {
var nodes []*Node var nodes []*Node
@ -277,42 +274,42 @@ func NewTree(hasher BaseHasher, segmentSize, segmentCount int) *Tree {
// methods needed by hash.Hash // methods needed by hash.Hash
// Size returns the size // Size returns the size
func (self *Hasher) Size() int { func (ha *Hasher) Size() int {
return self.size return ha.size
} }
// BlockSize returns the block size // BlockSize returns the block size
func (self *Hasher) BlockSize() int { func (ha *Hasher) BlockSize() int {
return self.blocksize return ha.blocksize
} }
// Sum returns the hash of the buffer // Sum returns the hash of the buffer
// hash.Hash interface Sum method appends the byte slice to the underlying // hash.Hash interface Sum method appends the byte slice to the underlying
// data before it calculates and returns the hash of the chunk // data before it calculates and returns the hash of the chunk
func (self *Hasher) Sum(b []byte) (r []byte) { func (ha *Hasher) Sum(b []byte) (r []byte) {
t := self.bmt t := ha.bmt
i := self.cur i := ha.cur
n := t.leaves[i] n := t.leaves[i]
j := i j := i
// must run strictly before all nodes calculate // must run strictly before all nodes calculate
// datanodes are guaranteed to have a parent // datanodes are guaranteed to have a parent
if len(self.segment) > self.size && i > 0 && n.parent != nil { if len(ha.segment) > ha.size && i > 0 && n.parent != nil {
n = n.parent n = n.parent
} else { } else {
i *= 2 i *= 2
} }
d := self.finalise(n, i) d := ha.finalise(n, i)
self.writeSegment(j, self.segment, d) ha.writeSegment(j, ha.segment, d)
c := <-self.result c := <-ha.result
self.releaseTree() ha.releaseTree()
// sha3(length + BMT(pure_chunk)) // sha3(length + BMT(pure_chunk))
if self.blockLength == nil { if ha.blockLength == nil {
return c return c
} }
res := self.pool.hasher() res := ha.pool.hasher()
res.Reset() res.Reset()
res.Write(self.blockLength) res.Write(ha.blockLength)
res.Write(c) res.Write(c)
return res.Sum(nil) return res.Sum(nil)
} }
@ -321,8 +318,8 @@ func (self *Hasher) Sum(b []byte) (r []byte) {
// Hash waits for the hasher result and returns it // Hash waits for the hasher result and returns it
// caller must call this on a BMT Hasher being written to // caller must call this on a BMT Hasher being written to
func (self *Hasher) Hash() []byte { func (ha *Hasher) Hash() []byte {
return <-self.result return <-ha.result
} }
// Hasher implements the io.Writer interface // Hasher implements the io.Writer interface
@ -330,16 +327,16 @@ func (self *Hasher) Hash() []byte {
// Write fills the buffer to hash // Write fills the buffer to hash
// with every full segment complete launches a hasher go routine // with every full segment complete launches a hasher go routine
// that shoots up the BMT // that shoots up the BMT
func (self *Hasher) Write(b []byte) (int, error) { func (ha *Hasher) Write(b []byte) (int, error) {
l := len(b) l := len(b)
if l <= 0 { if l <= 0 {
return 0, nil return 0, nil
} }
s := self.segment s := ha.segment
i := self.cur i := ha.cur
count := (self.count + 1) / 2 count := (ha.count + 1) / 2
need := self.count*self.size - self.cur*2*self.size need := ha.count*ha.size - ha.cur*2*ha.size
size := self.size size := ha.size
if need > size { if need > size {
size *= 2 size *= 2
} }
@ -356,7 +353,7 @@ func (self *Hasher) Write(b []byte) (int, error) {
// read full segments and the last possibly partial segment // read full segments and the last possibly partial segment
for need > 0 && i < count-1 { for need > 0 && i < count-1 {
// push all finished chunks we read // push all finished chunks we read
self.writeSegment(i, s, self.depth) ha.writeSegment(i, s, ha.depth)
need -= size need -= size
if need < 0 { if need < 0 {
size += need size += need
@ -365,8 +362,8 @@ func (self *Hasher) Write(b []byte) (int, error) {
rest += size rest += size
i++ i++
} }
self.segment = s ha.segment = s
self.cur = i ha.cur = i
// otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full // otherwise, we can assume len(s) == 0, so all buffer is read and chunk is not yet full
return l, nil return l, nil
} }
@ -376,8 +373,8 @@ func (self *Hasher) Write(b []byte) (int, error) {
// ReadFrom reads from io.Reader and appends to the data to hash using Write // ReadFrom reads from io.Reader and appends to the data to hash using Write
// it reads so that chunk to hash is maximum length or reader reaches EOF // it reads so that chunk to hash is maximum length or reader reaches EOF
// caller must Reset the hasher prior to call // caller must Reset the hasher prior to call
func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) { func (ha *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
bufsize := self.size*self.count - self.size*self.cur - len(self.segment) bufsize := ha.size*ha.count - ha.size*ha.cur - len(ha.segment)
buf := make([]byte, bufsize) buf := make([]byte, bufsize)
var read int var read int
for { for {
@ -385,7 +382,7 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
n, err = r.Read(buf) n, err = r.Read(buf)
read += n read += n
if err == io.EOF || read == len(buf) { if err == io.EOF || read == len(buf) {
hash := self.Sum(buf[:n]) hash := ha.Sum(buf[:n])
if read == len(buf) { if read == len(buf) {
err = NewEOC(hash) err = NewEOC(hash)
} }
@ -394,7 +391,7 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
if err != nil { if err != nil {
break break
} }
n, err = self.Write(buf[:n]) _, err = ha.Write(buf[:n])
if err != nil { if err != nil {
break break
} }
@ -403,9 +400,9 @@ func (self *Hasher) ReadFrom(r io.Reader) (m int64, err error) {
} }
// Reset needs to be called before writing to the hasher // Reset needs to be called before writing to the hasher
func (self *Hasher) Reset() { func (ha *Hasher) Reset() {
self.getTree() ha.getTree()
self.blockLength = nil ha.blockLength = nil
} }
// Hasher implements the SwarmHash interface // Hasher implements the SwarmHash interface
@ -413,53 +410,53 @@ func (self *Hasher) Reset() {
// ResetWithLength needs to be called before writing to the hasher // ResetWithLength needs to be called before writing to the hasher
// the argument is supposed to be the byte slice binary representation of // the argument is supposed to be the byte slice binary representation of
// the legth of the data subsumed under the hash // the legth of the data subsumed under the hash
func (self *Hasher) ResetWithLength(l []byte) { func (ha *Hasher) ResetWithLength(l []byte) {
self.Reset() ha.Reset()
self.blockLength = l ha.blockLength = l
} }
// Release gives back the Tree to the pool whereby it unlocks // Release gives back the Tree to the pool whereby it unlocks
// it resets tree, segment and index // it resets tree, segment and index
func (self *Hasher) releaseTree() { func (ha *Hasher) releaseTree() {
if self.bmt != nil { if ha.bmt != nil {
n := self.bmt.leaves[self.cur] n := ha.bmt.leaves[ha.cur]
for ; n != nil; n = n.parent { for ; n != nil; n = n.parent {
n.unbalanced = false n.unbalanced = false
if n.parent != nil { if n.parent != nil {
n.root = false n.root = false
} }
} }
self.pool.Release(self.bmt) ha.pool.Release(ha.bmt)
self.bmt = nil ha.bmt = nil
} }
self.cur = 0 ha.cur = 0
self.segment = nil ha.segment = nil
} }
func (self *Hasher) writeSegment(i int, s []byte, d int) { func (ha *Hasher) writeSegment(i int, s []byte, d int) {
h := self.pool.hasher() h := ha.pool.hasher()
n := self.bmt.leaves[i] n := ha.bmt.leaves[i]
if len(s) > self.size && n.parent != nil { if len(s) > ha.size && n.parent != nil {
go func() { go func() {
h.Reset() h.Reset()
h.Write(s) h.Write(s)
s = h.Sum(nil) s = h.Sum(nil)
if n.root { if n.root {
self.result <- s ha.result <- s
return return
} }
self.run(n.parent, h, d, n.index, s) ha.run(n.parent, h, d, n.index, s)
}() }()
return return
} }
go self.run(n, h, d, i*2, s) go ha.run(n, h, d, i*2, s)
} }
func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) { func (ha *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
isLeft := i%2 == 0 isLeft := i%2 == 0
for { for {
if isLeft { if isLeft {
@ -480,9 +477,9 @@ func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
s = append(n.left, n.right...) s = append(n.left, n.right...)
} }
self.hash = s ha.hash = s
if n.root { if n.root {
self.result <- s ha.result <- s
return return
} }
@ -493,20 +490,20 @@ func (self *Hasher) run(n *Node, h hash.Hash, d int, i int, s []byte) {
} }
// getTree obtains a BMT resource by reserving one from the pool // getTree obtains a BMT resource by reserving one from the pool
func (self *Hasher) getTree() *Tree { func (ha *Hasher) getTree() *Tree {
if self.bmt != nil { if ha.bmt != nil {
return self.bmt return ha.bmt
} }
t := self.pool.Reserve() t := ha.pool.Reserve()
self.bmt = t ha.bmt = t
return t return t
} }
// atomic bool toggle implementing a concurrent reusable 2-state object // atomic bool toggle implementing a concurrent reusable 2-state object
// atomic addint with %2 implements atomic bool toggle // atomic addint with %2 implements atomic bool toggle
// it returns true if the toggler just put it in the active/waiting state // it returns true if the toggler just put it in the active/waiting state
func (self *Node) toggle() bool { func (n *Node) toggle() bool {
return atomic.AddInt32(&self.state, 1)%2 == 1 return atomic.AddInt32(&n.state, 1)%2 == 1
} }
func hashstr(b []byte) string { func hashstr(b []byte) string {
@ -526,7 +523,7 @@ func depth(n int) (d int) {
// finalise is following the zigzags on the tree belonging // finalise is following the zigzags on the tree belonging
// to the final datasegment // to the final datasegment
func (self *Hasher) finalise(n *Node, i int) (d int) { func (ha *Hasher) finalise(n *Node, i int) (d int) {
isLeft := i%2 == 0 isLeft := i%2 == 0
for { for {
// when the final segment's path is going via left segments // when the final segment's path is going via left segments
@ -551,8 +548,8 @@ type EOC struct {
} }
// Error returns the error string // Error returns the error string
func (self *EOC) Error() string { func (e *EOC) Error() string {
return fmt.Sprintf("hasher limit reached, chunk hash: %x", self.Hash) return fmt.Sprintf("hasher limit reached, chunk hash: %x", e.Hash)
} }
// NewEOC creates new end of chunk error with the hash // NewEOC creates new end of chunk error with the hash

View file

@ -29,7 +29,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3" "golang.org/x/crypto/sha3"
) )
const ( const (
@ -39,7 +39,7 @@ const (
// TestRefHasher tests that the RefHasher computes the expected BMT hash for // TestRefHasher tests that the RefHasher computes the expected BMT hash for
// all data lengths between 0 and 256 bytes // all data lengths between 0 and 256 bytes
func TestRefHasher(t *testing.T) { func TestRefHasher(t *testing.T) {
hashFunc := sha3.NewKeccak256 hashFunc := sha3.NewLegacyKeccak256
sha3 := func(data ...[]byte) []byte { sha3 := func(data ...[]byte) []byte {
h := hashFunc() h := hashFunc()
@ -212,7 +212,7 @@ func testHasher(f func(BaseHasher, []byte, int, int) error) error {
tdata := testDataReader(4128) tdata := testDataReader(4128)
data := make([]byte, 4128) data := make([]byte, 4128)
tdata.Read(data) tdata.Read(data)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
size := hasher().Size() size := hasher().Size()
counts := []int{1, 2, 3, 4, 5, 8, 16, 32, 64, 128} counts := []int{1, 2, 3, 4, 5, 8, 16, 32, 64, 128}
@ -239,7 +239,7 @@ func TestHasherReuseWithRelease(t *testing.T) {
} }
func testHasherReuse(i int, t *testing.T) { func testHasherReuse(i int, t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, 128, i) pool := NewTreePool(hasher, 128, i)
defer pool.Drain(0) defer pool.Drain(0)
bmt := New(pool) bmt := New(pool)
@ -258,7 +258,7 @@ func testHasherReuse(i int, t *testing.T) {
} }
func TestHasherConcurrency(t *testing.T) { func TestHasherConcurrency(t *testing.T) {
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
pool := NewTreePool(hasher, 128, maxproccnt) pool := NewTreePool(hasher, 128, maxproccnt)
defer pool.Drain(0) defer pool.Drain(0)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
@ -379,7 +379,7 @@ func benchmarkBMTBaseline(n int, t *testing.B) {
tdata := testDataReader(64) tdata := testDataReader(64)
data := make([]byte, 64) data := make([]byte, 64)
tdata.Read(data) tdata.Read(data)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
t.ReportAllocs() t.ReportAllocs()
t.ResetTimer() t.ResetTimer()
@ -409,7 +409,7 @@ func benchmarkHasher(n int, t *testing.B) {
tdata.Read(data) tdata.Read(data)
size := 1 size := 1
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
segmentCount := 128 segmentCount := 128
pool := NewTreePool(hasher, segmentCount, size) pool := NewTreePool(hasher, segmentCount, size)
bmt := New(pool) bmt := New(pool)
@ -428,7 +428,7 @@ func benchmarkHasherReuse(poolsize, n int, t *testing.B) {
data := make([]byte, n) data := make([]byte, n)
tdata.Read(data) tdata.Read(data)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
segmentCount := 128 segmentCount := 128
pool := NewTreePool(hasher, segmentCount, poolsize) pool := NewTreePool(hasher, segmentCount, poolsize)
cycles := 200 cycles := 200
@ -455,7 +455,7 @@ func benchmarkSHA3(n int, t *testing.B) {
data := make([]byte, n) data := make([]byte, n)
tdata := testDataReader(n) tdata := testDataReader(n)
tdata.Read(data) tdata.Read(data)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
h := hasher() h := hasher()
t.ReportAllocs() t.ReportAllocs()
@ -471,7 +471,7 @@ func benchmarkRefHasher(n int, t *testing.B) {
data := make([]byte, n) data := make([]byte, n)
tdata := testDataReader(n) tdata := testDataReader(n)
tdata.Read(data) tdata.Read(data)
hasher := sha3.NewKeccak256 hasher := sha3.NewLegacyKeccak256
rbmt := NewRefHasher(hasher, 128) rbmt := NewRefHasher(hasher, 128)
t.ReportAllocs() t.ReportAllocs()

View file

@ -115,7 +115,7 @@ func doInstall(cmdline []string) {
if minor < 21 { if minor < 21 {
log.Println("You have Go version", runtime.Version()) log.Println("You have Go version", runtime.Version())
log.Println("XDC requires at least Go version 1.21 and cannot") log.Println("XDC requires at least Go version 1.22 and cannot")
log.Println("be compiled with an earlier version. Please upgrade your Go installation.") log.Println("be compiled with an earlier version. Please upgrade your Go installation.")
os.Exit(1) os.Exit(1)
} }

View file

@ -1,4 +1,4 @@
FROM golang:1.21-alpine as builder FROM golang:1.22-alpine as builder
RUN apk add make build-base linux-headers RUN apk add make build-base linux-headers

View file

@ -1,5 +1,2 @@
enode://207f812067141e038439acbd18a6e3b5f38fcff7de362d8fe0eb5f153f828ae99cae3270ed653beaa197e3946223d9e2f4a22a5e948177209d046fd095b89626@66.94.121.151:30301 enode://00d49d72a48164681906ad61924568da0d3049937efdbaed0b7533e34a99f55814f1839d909cdc82f78e04a36ac04737d80b41b22905c7d6cac3c80bb5cdbbc4@66.94.98.186:30301
enode://ec569f5d52cefee5c5405a0c5db720dc7061f3085e0682dd8321413430ddda6a177b85db75b0daf83d2e68760ba3f5beb4ba9e333e7d52072fba4d39b05a0451@194.233.77.19:30301 enode://d6793b02a478f13ed6d01c30778935f6f8f7461a75aebedcb310def4ed9b066f995a0dca046d0c7ea7f5ffdd8e3f1f53c6b6dce909d1693650504921aad62f1a@194.163.167.177:30301
enode://cab457c58bc9b94ea9afa428d018179b4773fe90fec16ef958951f5a23adb9627350cea8b56709351766183d85574fc54ba504816b200fa31675a04c25226e9f@66.94.98.186:30301
enode://751de9e39fe0b8f18585bb4a8b50aa5631fe262e14f579753709631eddcac30be901ca0b5a3878b7686838da7ddca2c61e6d2c5eb3745e6b855289e692068e8d@144.126.140.3:30301
enode://6bd073ee1085c1dc09427d9f65f0125a75393ac89f0db36f884cc22d61f441403a4c06d8f9a9d3c8e8c08368122bceeeac5f48c83f3d2e87c0da6d5c0eb7cd7e@194.163.167.177:30301

View file

@ -46,17 +46,17 @@ else
log_level=$LOG_LEVEL log_level=$LOG_LEVEL
fi fi
netstats="${NODE_NAME}-${wallet}-local:xinfin_xdpos_hybrid_network_stats@devnetstats.apothem.network:2000" netstats="${NODE_NAME}-${wallet}-local:xinfin_xdpos_hybrid_network_stats@devnetstats.hashlabs.apothem.network:1999"
echo "Running a node with wallet: ${wallet} at local" echo "Running a node with wallet: ${wallet} at local"
../../build/bin/XDC --ethstats ${netstats} --gcmode=archive \ ../../build/bin/XDC --ethstats ${netstats} --gcmode=archive \
--bootnodes ${bootnodes} --syncmode full \ --bootnodes ${bootnodes} --syncmode full \
--datadir ./tmp/xdcchain --networkid 551 \ --datadir ./tmp/xdcchain --networkid 551 \
-port 30303 --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \ --port 30303 --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--rpcport 8545 \ --http-port 8545 \
--rpcapi db,eth,debug,miner,net,shh,txpool,personal,web3,XDPoS \ --http-api db,eth,debug,miner,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password ./tmp/.pwd --mine \ --http-vhosts "*" --unlock "${wallet}" --password ./tmp/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \ --miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--ws --wsaddr=0.0.0.0 --wsport 8555 \ --ws --ws-addr=0.0.0.0 --ws-port 8555 \
--wsorigins "*" 2>&1 >>./tmp/xdc.log --ws-origins "*" 2>&1 >>./tmp/xdc.log

View file

@ -24,6 +24,13 @@ do
bootnodes="${bootnodes},$line" bootnodes="${bootnodes},$line"
fi fi
done < "$input" done < "$input"
#check last line since it's not included in "read" command https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line
if [ -z "${bootnodes}" ]
then
bootnodes=$line
else
bootnodes="${bootnodes},$line"
fi
log_level=3 log_level=3
if test -z "$LOG_LEVEL" if test -z "$LOG_LEVEL"
@ -62,7 +69,7 @@ else
fi fi
INSTANCE_IP=$(curl https://checkip.amazonaws.com) INSTANCE_IP=$(curl https://checkip.amazonaws.com)
netstats="${NODE_NAME}-${wallet}-${INSTANCE_IP}:xinfin_xdpos_hybrid_network_stats@devnetstats.apothem.network:2000" netstats="${NODE_NAME}-${wallet}-${INSTANCE_IP}:xinfin_xdpos_hybrid_network_stats@devnetstats.hashlabs.apothem.network:1999"
echo "Running a node with wallet: ${wallet} at IP: ${INSTANCE_IP}" echo "Running a node with wallet: ${wallet} at IP: ${INSTANCE_IP}"
@ -75,11 +82,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \ --nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \ --bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 551 \ --datadir /work/xdcchain --networkid 551 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \ --port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--rpcport $rpc_port \ --http-port $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \ --http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \ --http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \ --miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \ --debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \ --store-reward \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log --ws --ws-addr=0.0.0.0 --ws-port $ws_port \
--ws-origins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log

View file

@ -2,7 +2,6 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 5.13.1"
} }
} }
} }

View file

@ -2,7 +2,6 @@ terraform {
required_providers { required_providers {
aws = { aws = {
source = "hashicorp/aws" source = "hashicorp/aws"
version = "~> 5.13.1"
} }
} }
} }

View file

@ -1,4 +1,3 @@
# Bucket need to be created first. If first time run terraform init, need to comment out the below section
terraform { terraform {
backend "s3" { backend "s3" {
bucket = "tf-xinfin-bucket" // This name need to be updated to be the same as local.s3BucketName. We can't use variable here. bucket = "tf-xinfin-bucket" // This name need to be updated to be the same as local.s3BucketName. We can't use variable here.

View file

@ -5,15 +5,6 @@ variable docker_tag {
} }
locals { locals {
/**
Load the nodes data from s3
Below is the the format the config needs to follow:
{{Name of the node, in a pattern of 'xdc'+ number. i.e xdc50}}: {
pk: {{Value of the node private key}},
... any other configuration we want to pass.
}
Note: No `n` is allowed in the node name
**/
predefinedNodesConfig = jsondecode(data.aws_s3_object.devnet_xdc_node_config.body) predefinedNodesConfig = jsondecode(data.aws_s3_object.devnet_xdc_node_config.body)
envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] } envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] }
logLevel = local.envs["log_level"] logLevel = local.envs["log_level"]

View file

@ -24,6 +24,13 @@ do
bootnodes="${bootnodes},$line" bootnodes="${bootnodes},$line"
fi fi
done < "$input" done < "$input"
#check last line since it's not included in "read" command https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line
if [ -z "${bootnodes}" ]
then
bootnodes=$line
else
bootnodes="${bootnodes},$line"
fi
log_level=3 log_level=3
if test -z "$LOG_LEVEL" if test -z "$LOG_LEVEL"
@ -74,11 +81,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \ --nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \ --bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 50 \ --datadir /work/xdcchain --networkid 50 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \ --port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--rpcport $rpc_port \ --http-port $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \ --http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \ --http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \ --miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \ --debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \ --store-reward \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log --ws --ws-addr=0.0.0.0 --ws-port $ws_port \
--ws-origins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log

View file

@ -12,8 +12,6 @@ provider "aws" {
region = "us-east-1" region = "us-east-1"
} }
# WARNING: APSE-1 will only be used to host rpc node
# Workaround to avoid conflicts with existing ecs cluster in existing regions
provider "aws" { provider "aws" {
alias = "ap-southeast-1" alias = "ap-southeast-1"
region = "ap-southeast-1" region = "ap-southeast-1"
@ -25,7 +23,7 @@ module "devnet_rpc" {
vpc_id = local.vpc_id vpc_id = local.vpc_id
aws_subnet_id = local.aws_subnet_id aws_subnet_id = local.aws_subnet_id
ami_id = local.ami_id ami_id = local.ami_id
instance_type = "t3.xlarge" instance_type = "t3.large"
ssh_key_name = local.ssh_key_name ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image rpc_image = local.rpc_image
volume_size = 1500 volume_size = 1500

View file

@ -1,41 +1,14 @@
locals { locals {
/**
Load the nodes data from s3
Below is the the format the config needs to follow:
{{Name of the node, in a pattern of 'xdc'+ number. i.e xdc50}}: {
pk: {{Value of the node private key}},
... any other configuration we want to pass.
}
Note: No `n` is allowed in the node name
**/
predefinedNodesConfig = jsondecode(data.aws_s3_object.xdc_node_config.body) predefinedNodesConfig = jsondecode(data.aws_s3_object.xdc_node_config.body)
envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] } envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] }
logLevel = local.envs["log_level"] logLevel = local.envs["log_level"]
# regions = [
# {
# "name": "us-east-2", // Ohio
# "start": local.envs["us_east_2_start"],
# "end": local.envs["us_east_2_end"],
# }
# ]
# keyNames = {
# for r in local.regions :
# r.name => [for i in range(r.start, r.end+1) : "xdc${i}"]
# }
# nodeKeys = {
# for r in local.regions :
# r.name => { for i in local.keyNames[r.name]: i => local.predefinedNodesConfig[i] }
# }
rpcDevnetNodeKeys = { "devnet-rpc1": local.predefinedNodesConfig["devnet-rpc1"]} // we hardcode the rpc to a single node for now rpcDevnetNodeKeys = { "devnet-rpc1": local.predefinedNodesConfig["devnet-rpc1"]} // we hardcode the rpc to a single node for now
rpcTestnetNodeKeys = { "testnet-rpc1": local.predefinedNodesConfig["testnet-rpc1"]} // we hardcode the rpc to a single node for now rpcTestnetNodeKeys = { "testnet-rpc1": local.predefinedNodesConfig["testnet-rpc1"]} // we hardcode the rpc to a single node for now
rpcMainnetNodeKeys = { "mainnet-rpc1": local.predefinedNodesConfig["mainnet-rpc1"]} // we hardcode the rpc to a single node for now rpcMainnetNodeKeys = { "mainnet-rpc1": local.predefinedNodesConfig["mainnet-rpc1"]} // we hardcode the rpc to a single node for now
} }
locals { //ec2_rpc values locals {
ami_id = "ami-097c4e1feeea169e5" ami_id = "ami-097c4e1feeea169e5"
rpc_image = "xinfinorg/xdposchain:v2.2.0-beta1" rpc_image = "xinfinorg/xdposchain:v2.2.0-beta1"
vpc_id = "vpc-20a06846" vpc_id = "vpc-20a06846"

View file

@ -25,6 +25,13 @@ do
bootnodes="${bootnodes},$line" bootnodes="${bootnodes},$line"
fi fi
done < "$input" done < "$input"
#check last line since it's not included in "read" command https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line
if [ -z "${bootnodes}" ]
then
bootnodes=$line
else
bootnodes="${bootnodes},$line"
fi
log_level=3 log_level=3
if test -z "$LOG_LEVEL" if test -z "$LOG_LEVEL"
@ -76,11 +83,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \ --nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \ --bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 51 \ --datadir /work/xdcchain --networkid 51 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \ --port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--rpcport $rpc_port \ --http-port $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \ --http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \ --http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \ --miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \ --debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \ --store-reward \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log --ws --ws-addr=0.0.0.0 --ws-port $ws_port \
--ws-origins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log

View file

@ -26,31 +26,31 @@ import (
"github.com/XinFinOrg/XDPoSChain/console" "github.com/XinFinOrg/XDPoSChain/console"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
walletCommand = cli.Command{ walletCommand = &cli.Command{
Name: "wallet", Name: "wallet",
Usage: "Manage XDPoSChain presale wallets", Usage: "Manage XDPoSChain presale wallets",
ArgsUsage: "", ArgsUsage: "",
Category: "ACCOUNT COMMANDS",
Description: ` Description: `
XDC wallet import /path/to/my/presale.wallet XDC wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account. will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.`, passwordfile as argument containing the wallet password in plaintext.`,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "import", Name: "import",
Usage: "Import XDPoSChain presale wallet", Usage: "Import XDPoSChain presale wallet",
ArgsUsage: "<keyFile>", ArgsUsage: "<keyFile>",
Action: utils.MigrateFlags(importWallet), Action: importWallet,
Category: "ACCOUNT COMMANDS", Category: "ACCOUNT COMMANDS",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.PasswordFileFlag, utils.PasswordFileFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
@ -65,10 +65,9 @@ passwordfile as argument containing the wallet password in plaintext.`,
}, },
} }
accountCommand = cli.Command{ accountCommand = &cli.Command{
Name: "account", Name: "account",
Usage: "Manage accounts", Usage: "Manage accounts",
Category: "ACCOUNT COMMANDS",
Description: ` Description: `
Manage accounts, list all existing accounts, import a private key into a new Manage accounts, list all existing accounts, import a private key into a new
@ -89,13 +88,14 @@ It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying. between ethereum nodes by simply copying.
Make sure you backup your keys regularly.`, Make sure you backup your keys regularly.`,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "list", Name: "list",
Usage: "Print summary of existing accounts", Usage: "Print summary of existing accounts",
Action: utils.MigrateFlags(accountList), Action: accountList,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
}, },
Description: ` Description: `
@ -104,9 +104,10 @@ Print a short summary of all accounts`,
{ {
Name: "new", Name: "new",
Usage: "Create a new account", Usage: "Create a new account",
Action: utils.MigrateFlags(accountCreate), Action: accountCreate,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.PasswordFileFlag, utils.PasswordFileFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
@ -129,10 +130,11 @@ password to file or expose in any other way.
{ {
Name: "update", Name: "update",
Usage: "Update an existing account", Usage: "Update an existing account",
Action: utils.MigrateFlags(accountUpdate), Action: accountUpdate,
ArgsUsage: "<address>", ArgsUsage: "<address>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
}, },
@ -158,9 +160,10 @@ changing your password is only possible interactively.
{ {
Name: "import", Name: "import",
Usage: "Import a private key into a new account", Usage: "Import a private key into a new account",
Action: utils.MigrateFlags(accountImport), Action: accountImport,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
utils.PasswordFileFlag, utils.PasswordFileFlag,
utils.LightKDFFlag, utils.LightKDFFlag,
@ -293,7 +296,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
func accountCreate(ctx *cli.Context) error { func accountCreate(ctx *cli.Context) error {
cfg := XDCConfig{Node: defaultNodeConfig()} cfg := XDCConfig{Node: defaultNodeConfig()}
// Load config file. // Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" { if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil { if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
@ -319,13 +322,13 @@ func accountCreate(ctx *cli.Context) error {
// accountUpdate transitions an account from a previous format to the current // accountUpdate transitions an account from a previous format to the current
// one, also providing the possibility to change the pass-phrase. // one, also providing the possibility to change the pass-phrase.
func accountUpdate(ctx *cli.Context) error { func accountUpdate(ctx *cli.Context) error {
if len(ctx.Args()) == 0 { if ctx.Args().Len() == 0 {
utils.Fatalf("No accounts specified to update") utils.Fatalf("No accounts specified to update")
} }
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
for _, addr := range ctx.Args() { for _, addr := range ctx.Args().Slice() {
account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil) account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
if err := ks.Update(account, oldPassword, newPassword); err != nil { if err := ks.Update(account, oldPassword, newPassword); err != nil {
@ -336,10 +339,10 @@ func accountUpdate(ctx *cli.Context) error {
} }
func importWallet(ctx *cli.Context) error { func importWallet(ctx *cli.Context) error {
keyfile := ctx.Args().First() if ctx.Args().Len() != 1 {
if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as the only argument")
utils.Fatalf("keyfile must be given as argument")
} }
keyfile := ctx.Args().First()
keyJson, err := os.ReadFile(keyfile) keyJson, err := os.ReadFile(keyfile)
if err != nil { if err != nil {
utils.Fatalf("Could not read wallet file: %v", err) utils.Fatalf("Could not read wallet file: %v", err)
@ -358,10 +361,10 @@ func importWallet(ctx *cli.Context) error {
} }
func accountImport(ctx *cli.Context) error { func accountImport(ctx *cli.Context) error {
keyfile := ctx.Args().First() if ctx.Args().Len() != 1 {
if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as the only argument")
utils.Fatalf("keyfile must be given as argument")
} }
keyfile := ctx.Args().First()
key, err := crypto.LoadECDSA(keyfile) key, err := crypto.LoadECDSA(keyfile)
if err != nil { if err != nil {
utils.Fatalf("Failed to load the private key: %v", err) utils.Fatalf("Failed to load the private key: %v", err)

View file

@ -43,26 +43,31 @@ func tmpDatadirWithKeystore(t *testing.T) string {
} }
func TestAccountListEmpty(t *testing.T) { func TestAccountListEmpty(t *testing.T) {
XDC := runXDC(t, "account", "list") datadir := tmpdir(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, "account", "list", "--datadir", datadir)
XDC.ExpectExit() XDC.ExpectExit()
} }
func TestAccountList(t *testing.T) { func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
XDC := runXDC(t, "account", "list", "--datadir", datadir) defer os.RemoveAll(datadir)
defer XDC.ExpectExit() var want = `
if runtime.GOOS == "windows" {
XDC.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`)
} else {
XDC.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz
`) `
if runtime.GOOS == "windows" {
want = `
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`
}
{
geth := runXDC(t, "account", "list", "--datadir", datadir)
geth.Expect(want)
geth.ExpectExit()
} }
} }
@ -92,9 +97,8 @@ Fatal: Passphrases do not match
func TestAccountUpdate(t *testing.T) { func TestAccountUpdate(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
XDC := runXDC(t, "account", "update", defer os.RemoveAll(datadir)
"--datadir", datadir, "--lightkdf", XDC := runXDC(t, "account", "update", "--datadir", datadir, "--lightkdf", "f466859ead1932d743d622cb74fc058882e8648a")
"f466859ead1932d743d622cb74fc058882e8648a")
defer XDC.ExpectExit() defer XDC.ExpectExit()
XDC.Expect(` XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
@ -107,7 +111,9 @@ Repeat passphrase: {{.InputLine "foobar2"}}
} }
func TestWalletImport(t *testing.T) { func TestWalletImport(t *testing.T) {
XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") datadir := tmpdir(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, "wallet", "import", "--datadir", datadir, "--lightkdf", "testdata/guswallet.json")
defer XDC.ExpectExit() defer XDC.ExpectExit()
XDC.Expect(` XDC.Expect(`
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
@ -121,6 +127,36 @@ Address: {xdcd4584b5f6229b7be90727b0fc8c6b91bb427821f}
} }
} }
func TestAccountHelp(t *testing.T) {
geth := runXDC(t, "account", "-h")
geth.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
geth = runXDC(t, "account", "import", "-h")
geth.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
}
func importAccountWithExpect(t *testing.T, key string, expected string) {
dir := t.TempDir()
defer os.RemoveAll(dir)
keyfile := filepath.Join(dir, "key.prv")
if err := os.WriteFile(keyfile, []byte(key), 0600); err != nil {
t.Error(err)
}
passwordFile := filepath.Join(dir, "password.txt")
if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil {
t.Error(err)
}
geth := runXDC(t, "account", "import", "--lightkdf", "-password", passwordFile, keyfile)
defer geth.ExpectExit()
geth.Expect(expected)
}
func TestWalletImportBadPassword(t *testing.T) { func TestWalletImportBadPassword(t *testing.T) {
XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer XDC.ExpectExit() defer XDC.ExpectExit()
@ -133,10 +169,11 @@ Fatal: could not decrypt key with given passphrase
func TestUnlockFlag(t *testing.T) { func TestUnlockFlag(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "js", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--port", "0", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js") "testdata/empty.js")
XDC.Expect(` XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
@ -157,6 +194,7 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagWrongPassword(t *testing.T) { func TestUnlockFlagWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a") "--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
@ -176,10 +214,11 @@ Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could
// https://github.com/XinFinOrg/XDPoSChain/issues/1785 // https://github.com/XinFinOrg/XDPoSChain/issues/1785
func TestUnlockFlagMultiIndex(t *testing.T) { func TestUnlockFlagMultiIndex(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "js", "--datadir", datadir, "--nat", "none", "--nodiscover",
"--unlock", "0,2", "--maxpeers", "0", "--port", "0", "--unlock", "0,2",
"js", "testdata/empty.js") "testdata/empty.js")
XDC.Expect(` XDC.Expect(`
Unlocking account 0 | Attempt 1/3 Unlocking account 0 | Attempt 1/3
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
@ -203,10 +242,11 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagPasswordFile(t *testing.T) { func TestUnlockFlagPasswordFile(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "js", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--password", "testdata/passwords.txt", "--unlock", "0,2", "--port", "0", "--password", "testdata/passwords.txt", "--unlock", "0,2",
"js", "testdata/empty.js") "testdata/empty.js")
XDC.ExpectExit() XDC.ExpectExit()
wantMessages := []string{ wantMessages := []string{
@ -223,6 +263,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) { func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/wrong-passwords.txt", "--unlock", "0,2") "--password", "testdata/wrong-passwords.txt", "--unlock", "0,2")
@ -235,9 +276,9 @@ Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase)
func TestUnlockFlagAmbiguous(t *testing.T) { func TestUnlockFlagAmbiguous(t *testing.T) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
XDC := runXDC(t, XDC := runXDC(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", "js", "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--port", "0", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js") "testdata/empty.js")
defer XDC.ExpectExit() defer XDC.ExpectExit()
// Helper for the expect template, returns absolute keystore path. // Helper for the expect template, returns absolute keystore path.

View file

@ -28,17 +28,14 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/internal/browser" "github.com/XinFinOrg/XDPoSChain/cmd/internal/browser"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/urfave/cli/v2"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
cli "gopkg.in/urfave/cli.v1"
) )
var bugCommand = cli.Command{ var bugCommand = &cli.Command{
Action: utils.MigrateFlags(reportBug), Action: reportBug,
Name: "bug", Name: "bug",
Usage: "opens a window to report a bug on the XDC repo", Usage: "opens a window to report a bug on the XDC repo",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
} }
const issueUrl = "https://github.com/XinFinOrg/XDPoSChain/issues/new" const issueUrl = "https://github.com/XinFinOrg/XDPoSChain/issues/new"

View file

@ -35,22 +35,21 @@ import (
"github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/downloader"
"github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/event"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/metrics" "github.com/urfave/cli/v2"
"gopkg.in/urfave/cli.v1"
) )
var ( var (
initCommand = cli.Command{ initCommand = &cli.Command{
Action: utils.MigrateFlags(initGenesis), Action: initGenesis,
Name: "init", Name: "init",
Usage: "Bootstrap and initialize a new genesis block", Usage: "Bootstrap and initialize a new genesis block",
ArgsUsage: "<genesisPath>", ArgsUsage: "<genesisPath>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.LightModeFlag, utils.LightModeFlag,
utils.XDCTestnetFlag, utils.XDCTestnetFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The init command initializes a new genesis block and definition for the network. The init command initializes a new genesis block and definition for the network.
This is a destructive action and changes the network in which you will be This is a destructive action and changes the network in which you will be
@ -58,20 +57,32 @@ participating.
It expects the genesis file as argument.`, It expects the genesis file as argument.`,
} }
importCommand = cli.Command{ importCommand = &cli.Command{
Action: utils.MigrateFlags(importChain), Action: importChain,
Name: "import", Name: "import",
Usage: "Import a blockchain file", Usage: "Import a blockchain file",
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ", ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
utils.GCModeFlag, utils.GCModeFlag,
utils.CacheDatabaseFlag, utils.CacheDatabaseFlag,
utils.CacheGCFlag, utils.CacheGCFlag,
utils.MetricsEnabledFlag,
utils.MetricsEnabledExpensiveFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsEnableInfluxDBV2Flag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBTagsFlag,
utils.MetricsInfluxDBTokenFlag,
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The import command imports blocks from an RLP-encoded form. The form can be one file The import command imports blocks from an RLP-encoded form. The form can be one file
with several RLP-encoded blocks, or several files can be used. with several RLP-encoded blocks, or several files can be used.
@ -79,30 +90,31 @@ with several RLP-encoded blocks, or several files can be used.
If only one file is used, import error will result in failure. If several files are used, If only one file is used, import error will result in failure. If several files are used,
processing will proceed even if an individual RLP-file import failure occurs.`, processing will proceed even if an individual RLP-file import failure occurs.`,
} }
exportCommand = cli.Command{ exportCommand = &cli.Command{
Action: utils.MigrateFlags(exportChain), Action: exportChain,
Name: "export", Name: "export",
Usage: "Export blockchain into file", Usage: "Export blockchain into file",
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]", ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
Requires a first argument of the file to write to. Requires a first argument of the file to write to.
Optional second and third arguments control the first and Optional second and third arguments control the first and
last block to write. In this mode, the file will be appended last block to write. In this mode, the file will be appended
if already existing.`, if already existing.`,
} }
importPreimagesCommand = cli.Command{ importPreimagesCommand = &cli.Command{
Action: utils.MigrateFlags(importPreimages), Action: importPreimages,
Name: "import-preimages", Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream", Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>", ArgsUsage: "<datafile>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
}, },
@ -110,57 +122,58 @@ if already existing.`,
Description: ` Description: `
The import-preimages command imports hash preimages from an RLP encoded stream.`, The import-preimages command imports hash preimages from an RLP encoded stream.`,
} }
exportPreimagesCommand = cli.Command{ exportPreimagesCommand = &cli.Command{
Action: utils.MigrateFlags(exportPreimages), Action: exportPreimages,
Name: "export-preimages", Name: "export-preimages",
Usage: "Export the preimage database into an RLP stream", Usage: "Export the preimage database into an RLP stream",
ArgsUsage: "<dumpfile>", ArgsUsage: "<dumpfile>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The export-preimages command export hash preimages to an RLP encoded stream`, The export-preimages command export hash preimages to an RLP encoded stream`,
} }
copydbCommand = cli.Command{ copydbCommand = &cli.Command{
Action: utils.MigrateFlags(copyDb), Action: copyDb,
Name: "copydb", Name: "copydb",
Usage: "Create a local chain from a target chaindata folder", Usage: "Create a local chain from a target chaindata folder",
ArgsUsage: "<sourceChaindataDir>", ArgsUsage: "<sourceChaindataDir>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
utils.FakePoWFlag, utils.FakePoWFlag,
utils.TestnetFlag, utils.TestnetFlag,
utils.RinkebyFlag, utils.RinkebyFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The first argument must be the directory containing the blockchain to download from`, The first argument must be the directory containing the blockchain to download from`,
} }
removedbCommand = cli.Command{ removedbCommand = &cli.Command{
Action: utils.MigrateFlags(removeDB), Action: removeDB,
Name: "removedb", Name: "removedb",
Usage: "Remove blockchain and state databases", Usage: "Remove blockchain and state databases",
ArgsUsage: " ", ArgsUsage: " ",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.LightModeFlag, utils.LightModeFlag,
}, },
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
Remove blockchain and state databases`, Remove blockchain and state databases`,
} }
dumpCommand = cli.Command{ dumpCommand = &cli.Command{
Action: utils.MigrateFlags(dump), Action: dump,
Name: "dump", Name: "dump",
Usage: "Dump a specific block from storage", Usage: "Dump a specific block from storage",
ArgsUsage: "[<blockHash> | <blockNum>]...", ArgsUsage: "[<blockHash> | <blockNum>]...",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag, utils.CacheFlag,
utils.LightModeFlag, utils.LightModeFlag,
}, },
@ -174,12 +187,10 @@ Use "ethereum dump 0" to dump the genesis block.`,
// initGenesis will initialise the given JSON format genesis file and writes it as // initGenesis will initialise the given JSON format genesis file and writes it as
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed. // the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
func initGenesis(ctx *cli.Context) error { func initGenesis(ctx *cli.Context) error {
// Make sure we have a valid genesis JSON
genesisPath := ctx.Args().First()
genesis := new(core.Genesis) genesis := new(core.Genesis)
if ctx.GlobalBool(utils.XDCTestnetFlag.Name) { if ctx.Bool(utils.XDCTestnetFlag.Name) {
if len(genesisPath) > 0 { if ctx.Args().Len() > 0 {
utils.Fatalf("Flags --apothem and genesis file can't be used at the same time") utils.Fatalf("Flags --apothem and genesis file can't be used at the same time")
} }
err := json.Unmarshal(apothemGenesis, &genesis) err := json.Unmarshal(apothemGenesis, &genesis)
@ -187,8 +198,12 @@ func initGenesis(ctx *cli.Context) error {
utils.Fatalf("invalid genesis json: %v", err) utils.Fatalf("invalid genesis json: %v", err)
} }
} else { } else {
if ctx.Args().Len() != 1 {
utils.Fatalf("need genesis.json file as the only argument")
}
genesisPath := ctx.Args().First()
if len(genesisPath) == 0 { if len(genesisPath) == 0 {
utils.Fatalf("Must supply path to genesis JSON file") utils.Fatalf("invalid path to genesis file")
} }
file, err := os.Open(genesisPath) file, err := os.Open(genesisPath)
if err != nil { if err != nil {
@ -203,6 +218,8 @@ func initGenesis(ctx *cli.Context) error {
// Open an initialise both full and light databases // Open an initialise both full and light databases
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} { for _, name := range []string{"chaindata", "lightchaindata"} {
chaindb, err := stack.OpenDatabase(name, 0, 0, "") chaindb, err := stack.OpenDatabase(name, 0, 0, "")
if err != nil { if err != nil {
@ -218,16 +235,15 @@ func initGenesis(ctx *cli.Context) error {
} }
func importChain(ctx *cli.Context) error { func importChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
stack, cfg := makeFullNode(ctx)
defer stack.Close()
// Start metrics export if enabled // Start metrics export if enabled
utils.SetupMetrics(ctx) utils.SetupMetrics(&cfg.Metrics)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
stack, _ := makeFullNode(ctx)
chain, chainDb := utils.MakeChain(ctx, stack) chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close() defer chainDb.Close()
@ -249,12 +265,12 @@ func importChain(ctx *cli.Context) error {
// Import the chain // Import the chain
start := time.Now() start := time.Now()
if len(ctx.Args()) == 1 { if ctx.Args().Len() == 1 {
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
log.Error("Import error", "err", err) log.Error("Import error", "err", err)
} }
} else { } else {
for _, arg := range ctx.Args() { for _, arg := range ctx.Args().Slice() {
if err := utils.ImportChain(chain, arg); err != nil { if err := utils.ImportChain(chain, arg); err != nil {
log.Error("Import error", "file", arg, "err", err) log.Error("Import error", "file", arg, "err", err)
} }
@ -287,7 +303,7 @@ func importChain(ctx *cli.Context) error {
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) { if ctx.IsSet(utils.NoCompactionFlag.Name) {
return nil return nil
} }
@ -315,17 +331,20 @@ func importChain(ctx *cli.Context) error {
} }
func exportChain(ctx *cli.Context) error { func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack) chain, db := utils.MakeChain(ctx, stack)
defer db.Close() defer db.Close()
start := time.Now() start := time.Now()
var err error var err error
fp := ctx.Args().First() fp := ctx.Args().First()
if len(ctx.Args()) < 3 { if ctx.Args().Len() < 3 {
err = utils.ExportChain(chain, fp) err = utils.ExportChain(chain, fp)
} else { } else {
// This can be improved to allow for numbers larger than 9223372036854775807 // This can be improved to allow for numbers larger than 9223372036854775807
@ -349,10 +368,13 @@ func exportChain(ctx *cli.Context) error {
// importPreimages imports preimage data from the specified file. // importPreimages imports preimage data from the specified file.
func importPreimages(ctx *cli.Context) error { func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
diskdb := utils.MakeChainDatabase(ctx, stack) diskdb := utils.MakeChainDatabase(ctx, stack)
defer diskdb.Close() defer diskdb.Close()
@ -366,10 +388,12 @@ func importPreimages(ctx *cli.Context) error {
// exportPreimages dumps the preimage data to specified json file in streaming way. // exportPreimages dumps the preimage data to specified json file in streaming way.
func exportPreimages(ctx *cli.Context) error { func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
diskdb := utils.MakeChainDatabase(ctx, stack) diskdb := utils.MakeChainDatabase(ctx, stack)
defer diskdb.Close() defer diskdb.Close()
@ -383,19 +407,24 @@ func exportPreimages(ctx *cli.Context) error {
func copyDb(ctx *cli.Context) error { func copyDb(ctx *cli.Context) error {
// Ensure we have a source chain directory to copy // Ensure we have a source chain directory to copy
if len(ctx.Args()) != 1 { if ctx.Args().Len() != 1 {
utils.Fatalf("Source chaindata directory path argument missing") utils.Fatalf("Source chaindata directory path argument missing")
} }
// Initialize a new chain for the running node to sync into // Initialize a new chain for the running node to sync into
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack) chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close() defer chainDb.Close()
syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode) var syncmode downloader.SyncMode
if err := syncmode.UnmarshalText([]byte(ctx.String(utils.SyncModeFlag.Name))); err != nil {
utils.Fatalf("invalid --syncmode flag: %v", err)
}
dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil, nil) dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil, nil)
// Create a source peer to satisfy downloader requests from // Create a source peer to satisfy downloader requests from
db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256, "") db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.Int(utils.CacheFlag.Name), 256, "")
if err != nil { if err != nil {
return err return err
} }
@ -461,10 +490,12 @@ func removeDB(ctx *cli.Context) error {
func dump(ctx *cli.Context) error { func dump(ctx *cli.Context) error {
stack, _ := makeFullNode(ctx) stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack) chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close() defer chainDb.Close()
for _, arg := range ctx.Args() { for _, arg := range ctx.Args().Slice() {
var block *types.Block var block *types.Block
if hashish(arg) { if hashish(arg) {
block = chain.GetBlockByHash(common.HexToHash(arg)) block = chain.GetBlockByHash(common.HexToHash(arg))

View file

@ -27,34 +27,33 @@ import (
"strings" "strings"
"unicode" "unicode"
"gopkg.in/urfave/cli.v1"
"github.com/XinFinOrg/XDPoSChain/XDCx" "github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/eth/ethconfig" "github.com/XinFinOrg/XDPoSChain/eth/ethconfig"
"github.com/XinFinOrg/XDPoSChain/internal/debug" "github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/metrics"
"github.com/XinFinOrg/XDPoSChain/node" "github.com/XinFinOrg/XDPoSChain/node"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
whisper "github.com/XinFinOrg/XDPoSChain/whisper/whisperv6"
"github.com/naoina/toml" "github.com/naoina/toml"
"github.com/urfave/cli/v2"
) )
var ( var (
dumpConfigCommand = cli.Command{ dumpConfigCommand = &cli.Command{
Action: utils.MigrateFlags(dumpConfig), Action: dumpConfig,
Name: "dumpconfig", Name: "dumpconfig",
Usage: "Show configuration values", Usage: "Show configuration values",
ArgsUsage: "", ArgsUsage: "",
Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...), Flags: utils.GroupFlags(nodeFlags, rpcFlags),
Category: "MISCELLANEOUS COMMANDS",
Description: `The dumpconfig command shows configuration values.`, Description: `The dumpconfig command shows configuration values.`,
} }
configFileFlag = cli.StringFlag{ configFileFlag = &cli.StringFlag{
Name: "config", Name: "config",
Usage: "TOML configuration file", Usage: "TOML configuration file",
Category: flags.EthCategory,
} }
) )
@ -91,9 +90,9 @@ type Bootnodes struct {
type XDCConfig struct { type XDCConfig struct {
Eth ethconfig.Config Eth ethconfig.Config
Shh whisper.Config
Node node.Config Node node.Config
Ethstats ethstatsConfig Ethstats ethstatsConfig
Metrics metrics.Config
XDCX XDCx.Config XDCX XDCx.Config
Account account Account account
StakeEnable bool StakeEnable bool
@ -120,42 +119,43 @@ func defaultNodeConfig() node.Config {
cfg := node.DefaultConfig cfg := node.DefaultConfig
cfg.Name = clientIdentifier cfg.Name = clientIdentifier
cfg.Version = params.VersionWithCommit(gitCommit) cfg.Version = params.VersionWithCommit(gitCommit)
cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh") cfg.HTTPModules = append(cfg.HTTPModules, "eth")
cfg.WSModules = append(cfg.WSModules, "eth", "shh") cfg.WSModules = append(cfg.WSModules, "eth")
cfg.IPCPath = "XDC.ipc" cfg.IPCPath = "XDC.ipc"
return cfg return cfg
} }
// makeConfigNode loads geth configuration and creates a blank node instance.
func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) { func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
// Load defaults. // Load defaults.
cfg := XDCConfig{ cfg := XDCConfig{
Eth: ethconfig.Defaults, Eth: ethconfig.Defaults,
Shh: whisper.DefaultConfig,
XDCX: XDCx.DefaultConfig, XDCX: XDCx.DefaultConfig,
Node: defaultNodeConfig(), Node: defaultNodeConfig(),
Metrics: metrics.DefaultConfig,
StakeEnable: true, StakeEnable: true,
Verbosity: 3, Verbosity: 3,
NAT: "", NAT: "",
} }
// Load config file. // Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" { if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil { if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
} }
if ctx.GlobalIsSet(utils.StakingEnabledFlag.Name) { if ctx.IsSet(utils.MiningEnabledFlag.Name) {
cfg.StakeEnable = ctx.GlobalBool(utils.StakingEnabledFlag.Name) cfg.StakeEnable = ctx.Bool(utils.MiningEnabledFlag.Name)
}
if !ctx.GlobalIsSet(debug.VerbosityFlag.Name) {
debug.Glogger.Verbosity(log.Lvl(cfg.Verbosity))
} }
// if !ctx.IsSet(debug.VerbosityFlag.Name) {
// debug.Verbosity(log.Lvl(cfg.Verbosity))
// }
if !ctx.GlobalIsSet(utils.NATFlag.Name) && cfg.NAT != "" { if !ctx.IsSet(utils.NATFlag.Name) && cfg.NAT != "" {
ctx.Set(utils.NATFlag.Name, cfg.NAT) ctx.Set(utils.NATFlag.Name, cfg.NAT)
} }
// Check testnet is enable. // Check testnet is enable.
if ctx.GlobalBool(utils.XDCTestnetFlag.Name) { if ctx.Bool(utils.XDCTestnetFlag.Name) {
common.IsTestnet = true common.IsTestnet = true
common.TRC21IssuerSMC = common.TRC21IssuerSMCTestNet common.TRC21IssuerSMC = common.TRC21IssuerSMCTestNet
cfg.Eth.NetworkId = 51 cfg.Eth.NetworkId = 51
@ -164,24 +164,24 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
common.TIPXDCXCancellationFee = common.TIPXDCXCancellationFeeTestnet common.TIPXDCXCancellationFee = common.TIPXDCXCancellationFeeTestnet
} }
if ctx.GlobalBool(utils.EnableXDCPrefixFlag.Name) { if ctx.Bool(utils.EnableXDCPrefixFlag.Name) {
common.Enable0xPrefix = false common.Enable0xPrefix = false
} }
// Rewound // Rewound
if rewound := ctx.GlobalInt(utils.RewoundFlag.Name); rewound != 0 { if rewound := ctx.Int(utils.RewoundFlag.Name); rewound != 0 {
common.Rewound = uint64(rewound) common.Rewound = uint64(rewound)
} }
// Check rollback hash exist. // Check rollback hash exist.
if rollbackHash := ctx.GlobalString(utils.RollbackFlag.Name); rollbackHash != "" { if rollbackHash := ctx.String(utils.RollbackFlag.Name); rollbackHash != "" {
common.RollbackHash = common.HexToHash(rollbackHash) common.RollbackHash = common.HexToHash(rollbackHash)
} }
// Check GasPrice // Check GasPrice
common.MinGasPrice = big.NewInt(common.DefaultMinGasPrice) common.MinGasPrice = big.NewInt(common.DefaultMinGasPrice)
if ctx.GlobalIsSet(utils.GasPriceFlag.Name) { if ctx.IsSet(utils.MinerGasPriceFlag.Name) {
if gasPrice := int64(ctx.GlobalInt(utils.GasPriceFlag.Name)); gasPrice > common.DefaultMinGasPrice { if gasPrice := int64(ctx.Int(utils.MinerGasPriceFlag.Name)); gasPrice > common.DefaultMinGasPrice {
common.MinGasPrice = big.NewInt(gasPrice) common.MinGasPrice = big.NewInt(gasPrice)
} }
} }
@ -208,12 +208,14 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
utils.Fatalf("Failed to create the protocol stack: %v", err) utils.Fatalf("Failed to create the protocol stack: %v", err)
} }
utils.SetEthConfig(ctx, stack, &cfg.Eth) utils.SetEthConfig(ctx, stack, &cfg.Eth)
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { if ctx.IsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name)
} }
utils.SetShhConfig(ctx, stack, &cfg.Shh)
utils.SetXDCXConfig(ctx, &cfg.XDCX, cfg.Node.DataDir) utils.SetXDCXConfig(ctx, &cfg.XDCX, cfg.Node.DataDir)
applyMetricConfig(ctx, &cfg)
return stack, cfg return stack, cfg
} }
@ -230,36 +232,16 @@ func applyValues(values []string, params *[]string) {
} }
// enableWhisper returns true in case one of the whisper flags is set.
func enableWhisper(ctx *cli.Context) bool {
for _, flag := range whisperFlags {
if ctx.GlobalIsSet(flag.GetName()) {
return true
}
}
return false
}
func makeFullNode(ctx *cli.Context) (*node.Node, XDCConfig) { func makeFullNode(ctx *cli.Context) (*node.Node, XDCConfig) {
stack, cfg := makeConfigNode(ctx) stack, cfg := makeConfigNode(ctx)
// Start metrics export if enabled
utils.SetupMetrics(&cfg.Metrics)
// Register XDCX's OrderBook service if requested. // Register XDCX's OrderBook service if requested.
// enable in default // enable in default
utils.RegisterXDCXService(stack, &cfg.XDCX) utils.RegisterXDCXService(stack, &cfg.XDCX)
utils.RegisterEthService(stack, &cfg.Eth) utils.RegisterEthService(stack, &cfg.Eth, cfg.Node.Version)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx)
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
if shhEnabled || shhAutoEnabled {
if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) {
cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name))
}
if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name)
}
utils.RegisterShhService(stack, &cfg.Shh)
}
// Add the Ethereum Stats daemon if requested. // Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" { if cfg.Ethstats.URL != "" {
@ -287,3 +269,69 @@ func dumpConfig(ctx *cli.Context) error {
os.Stdout.Write(out) os.Stdout.Write(out)
return nil return nil
} }
func applyMetricConfig(ctx *cli.Context, cfg *XDCConfig) {
if ctx.IsSet(utils.MetricsEnabledFlag.Name) {
cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name)
}
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
log.Warn("Expensive metrics are collected by default, please remove this flag", "flag", utils.MetricsEnabledExpensiveFlag.Name)
}
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
}
if ctx.IsSet(utils.MetricsPortFlag.Name) {
cfg.Metrics.Port = ctx.Int(utils.MetricsPortFlag.Name)
}
if ctx.IsSet(utils.MetricsEnableInfluxDBFlag.Name) {
cfg.Metrics.EnableInfluxDB = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBEndpointFlag.Name) {
cfg.Metrics.InfluxDBEndpoint = ctx.String(utils.MetricsInfluxDBEndpointFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBDatabaseFlag.Name) {
cfg.Metrics.InfluxDBDatabase = ctx.String(utils.MetricsInfluxDBDatabaseFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) {
cfg.Metrics.InfluxDBUsername = ctx.String(utils.MetricsInfluxDBUsernameFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) {
cfg.Metrics.InfluxDBPassword = ctx.String(utils.MetricsInfluxDBPasswordFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) {
cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name)
}
if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) {
cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) {
cfg.Metrics.InfluxDBToken = ctx.String(utils.MetricsInfluxDBTokenFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) {
cfg.Metrics.InfluxDBBucket = ctx.String(utils.MetricsInfluxDBBucketFlag.Name)
}
if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) {
cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name)
}
// Sanity-check the commandline flags. It is fine if some unused fields is part
// of the toml-config, but we expect the commandline to only contain relevant
// arguments, otherwise it indicates an error.
var (
enableExport = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
enableExportV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
)
if enableExport || enableExportV2 {
v1FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name)
v2FlagIsSet := ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) ||
ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name)
if enableExport && v2FlagIsSet {
utils.Fatalf("Flags --influxdb-metrics.organization, --influxdb-metrics.token, --influxdb-metrics.bucket are only available for influxdb-v2")
} else if enableExportV2 && v1FlagIsSet {
utils.Fatalf("Flags --influxdb-metrics.username, --influxdb-metrics.password are only available for influxdb-v1")
}
}
}

View file

@ -28,31 +28,29 @@ import (
"github.com/XinFinOrg/XDPoSChain/console" "github.com/XinFinOrg/XDPoSChain/console"
"github.com/XinFinOrg/XDPoSChain/node" "github.com/XinFinOrg/XDPoSChain/node"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
consoleCommand = cli.Command{ consoleCommand = &cli.Command{
Action: utils.MigrateFlags(localConsole), Action: localConsole,
Name: "console", Name: "console",
Usage: "Start an interactive JavaScript environment", Usage: "Start an interactive JavaScript environment",
Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...), Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The XDC console is an interactive shell for the JavaScript runtime environment The XDC console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console.`, See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console.`,
} }
attachCommand = cli.Command{ attachCommand = &cli.Command{
Action: utils.MigrateFlags(remoteConsole), Action: remoteConsole,
Name: "attach", Name: "attach",
Usage: "Start an interactive JavaScript environment (connect to node)", Usage: "Start an interactive JavaScript environment (connect to node)",
ArgsUsage: "[endpoint]", ArgsUsage: "[endpoint]",
Flags: append(consoleFlags, utils.DataDirFlag), Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The XDC console is an interactive shell for the JavaScript runtime environment The XDC console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
@ -60,13 +58,12 @@ See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console.
This command allows to open a console on a running XDC node.`, This command allows to open a console on a running XDC node.`,
} }
javascriptCommand = cli.Command{ javascriptCommand = &cli.Command{
Action: utils.MigrateFlags(ephemeralConsole), Action: ephemeralConsole,
Name: "js", Name: "js",
Usage: "Execute the specified JavaScript files", Usage: "Execute the specified JavaScript files",
ArgsUsage: "<jsfile> [jsfile...]", ArgsUsage: "<jsfile> [jsfile...]",
Flags: append(nodeFlags, consoleFlags...), Flags: utils.GroupFlags(nodeFlags, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console`, JavaScript API. See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console`,
@ -79,7 +76,7 @@ func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags // Create and start the node based on the CLI flags
node, cfg := makeFullNode(ctx) node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg) startNode(ctx, node, cfg)
defer node.Stop() defer node.Close()
// Attach to the newly started node and start the JavaScript console // Attach to the newly started node and start the JavaScript console
client, err := node.Attach() client, err := node.Attach()
@ -88,7 +85,7 @@ func localConsole(ctx *cli.Context) error {
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client, Client: client,
Preload: utils.MakeConsolePreloads(ctx), Preload: utils.MakeConsolePreloads(ctx),
} }
@ -100,7 +97,7 @@ func localConsole(ctx *cli.Context) error {
defer console.Stop(false) defer console.Stop(false)
// If only a short execution was requested, evaluate and return // If only a short execution was requested, evaluate and return
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script) console.Evaluate(script)
return nil return nil
} }
@ -114,17 +111,20 @@ func localConsole(ctx *cli.Context) error {
// remoteConsole will connect to a remote XDC instance, attaching a JavaScript // remoteConsole will connect to a remote XDC instance, attaching a JavaScript
// console to it. // console to it.
func remoteConsole(ctx *cli.Context) error { func remoteConsole(ctx *cli.Context) error {
// Attach to a remotely running XDC instance and start the JavaScript console if ctx.Args().Len() > 1 {
utils.Fatalf("invalid command-line: too many arguments")
}
endpoint := ctx.Args().First() endpoint := ctx.Args().First()
if endpoint == "" { if endpoint == "" {
path := node.DefaultDataDir() path := node.DefaultDataDir()
if ctx.GlobalIsSet(utils.DataDirFlag.Name) { if ctx.IsSet(utils.DataDirFlag.Name) {
path = ctx.GlobalString(utils.DataDirFlag.Name) path = ctx.String(utils.DataDirFlag.Name)
} }
if path != "" { if path != "" {
if ctx.GlobalBool(utils.TestnetFlag.Name) { if ctx.Bool(utils.TestnetFlag.Name) {
path = filepath.Join(path, "testnet") path = filepath.Join(path, "testnet")
} else if ctx.GlobalBool(utils.RinkebyFlag.Name) { } else if ctx.Bool(utils.RinkebyFlag.Name) {
path = filepath.Join(path, "rinkeby") path = filepath.Join(path, "rinkeby")
} }
} }
@ -137,7 +137,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client, Client: client,
Preload: utils.MakeConsolePreloads(ctx), Preload: utils.MakeConsolePreloads(ctx),
} }
@ -148,7 +148,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
defer console.Stop(false) defer console.Stop(false)
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script) console.Evaluate(script)
return nil return nil
} }
@ -181,7 +181,7 @@ func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags // Create and start the node based on the CLI flags
node, cfg := makeFullNode(ctx) node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg) startNode(ctx, node, cfg)
defer node.Stop() defer node.Close()
// Attach to the newly started node and start the JavaScript console // Attach to the newly started node and start the JavaScript console
client, err := node.Attach() client, err := node.Attach()
@ -190,7 +190,7 @@ func ephemeralConsole(ctx *cli.Context) error {
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client, Client: client,
Preload: utils.MakeConsolePreloads(ctx), Preload: utils.MakeConsolePreloads(ctx),
} }
@ -202,7 +202,7 @@ func ephemeralConsole(ctx *cli.Context) error {
defer console.Stop(false) defer console.Stop(false)
// Evaluate each of the specified JavaScript files // Evaluate each of the specified JavaScript files
for _, file := range ctx.Args() { for _, file := range ctx.Args().Slice() {
if err = console.Execute(file); err != nil { if err = console.Execute(file); err != nil {
utils.Fatalf("Failed to execute %s: %v", file, err) utils.Fatalf("Failed to execute %s: %v", file, err)
} }

View file

@ -39,13 +39,14 @@ const (
// then terminated by closing the input stream. // then terminated by closing the input stream.
func TestConsoleWelcome(t *testing.T) { func TestConsoleWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
// Start a XDC console, make sure it's cleaned up and terminate the console // Start a XDC console, make sure it's cleaned up and terminate the console
XDC := runXDC(t, XDC := runXDC(t,
"--XDCx.datadir", tmpdir(t)+"XDCx/"+time.Now().String(), "console", "--datadir", datadir, "--XDCx-datadir", datadir+"/XDCx/"+time.Now().String(),
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--miner-etherbase", coinbase)
"console")
// Gather all the infos the welcome message needs to contain // Gather all the infos the welcome message needs to contain
XDC.SetTemplateFunc("goos", func() string { return runtime.GOOS }) XDC.SetTemplateFunc("goos", func() string { return runtime.GOOS })
@ -76,18 +77,18 @@ at block: 0 ({{niltime}})
func TestIPCAttachWelcome(t *testing.T) { func TestIPCAttachWelcome(t *testing.T) {
// Configure the instance for IPC attachement // Configure the instance for IPC attachement
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
var ipc string var ipc string
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
ipc = `\\.\pipe\XDC` + strconv.Itoa(trulyRandInt(100000, 999999)) ipc = `\\.\pipe\XDC` + strconv.Itoa(trulyRandInt(100000, 999999))
} else { } else {
ws := tmpdir(t) ipc = filepath.Join(datadir, "XDC.ipc")
defer os.RemoveAll(ws)
ipc = filepath.Join(ws, "XDC.ipc")
} }
XDC := runXDC(t, XDC := runXDC(t,
"--XDCx.datadir", tmpdir(t)+"XDCx/"+time.Now().String(), "--datadir", datadir, "--XDCx-datadir", datadir+"/XDCx/"+time.Now().String(),
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--ipcpath", ipc) "--miner-etherbase", coinbase, "--ipcpath", ipc)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, XDC, "ipc:"+ipc, ipcAPIs) testAttachWelcome(t, XDC, "ipc:"+ipc, ipcAPIs)
@ -99,10 +100,12 @@ func TestIPCAttachWelcome(t *testing.T) {
func TestHTTPAttachWelcome(t *testing.T) { func TestHTTPAttachWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--XDCx.datadir", tmpdir(t)+"XDCx/"+time.Now().String(), "--datadir", datadir, "--XDCx-datadir", datadir+"/XDCx/"+time.Now().String(),
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--rpc", "--rpcport", port) "--miner-etherbase", coinbase, "--http", "--http-port", port)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, XDC, "http://localhost:"+port, httpAPIs) testAttachWelcome(t, XDC, "http://localhost:"+port, httpAPIs)
@ -114,11 +117,12 @@ func TestHTTPAttachWelcome(t *testing.T) {
func TestWSAttachWelcome(t *testing.T) { func TestWSAttachWelcome(t *testing.T) {
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, XDC := runXDC(t,
"--XDCx.datadir", tmpdir(t)+"XDCx/"+time.Now().String(), "--datadir", datadir, "--XDCx-datadir", datadir+"/XDCx/"+time.Now().String(),
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
"--etherbase", coinbase, "--ws", "--wsport", port) "--miner-etherbase", coinbase, "--ws", "--ws-port", port)
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
testAttachWelcome(t, XDC, "ws://localhost:"+port, httpAPIs) testAttachWelcome(t, XDC, "ws://localhost:"+port, httpAPIs)

View file

@ -111,11 +111,10 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
if err := os.WriteFile(json, []byte(genesis), 0600); err != nil { if err := os.WriteFile(json, []byte(genesis), 0600); err != nil {
t.Fatalf("test %d: failed to write genesis file: %v", test, err) t.Fatalf("test %d: failed to write genesis file: %v", test, err)
} }
runXDC(t, "--datadir", datadir, "init", json).WaitExit() runXDC(t, "init", "--datadir", datadir, json).WaitExit()
} else { } else {
// Force chain initialization // Force chain initialization
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir} XDC := runXDC(t, "console", "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir, "--exec", "2+2")
XDC := runXDC(t, append(args, []string{"--exec", "2+2", "console"}...)...)
XDC.WaitExit() XDC.WaitExit()
} }
// Retrieve the DAO config flag from the database // Retrieve the DAO config flag from the database

View file

@ -33,14 +33,14 @@ import (
"github.com/XinFinOrg/XDPoSChain/eth" "github.com/XinFinOrg/XDPoSChain/eth"
"github.com/XinFinOrg/XDPoSChain/ethclient" "github.com/XinFinOrg/XDPoSChain/ethclient"
"github.com/XinFinOrg/XDPoSChain/internal/debug" "github.com/XinFinOrg/XDPoSChain/internal/debug"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/metrics" "github.com/XinFinOrg/XDPoSChain/metrics"
"github.com/XinFinOrg/XDPoSChain/node" "github.com/XinFinOrg/XDPoSChain/node"
"github.com/urfave/cli/v2"
// Force-load the native, to trigger registration // Force-load the native, to trigger registration
_ "github.com/XinFinOrg/XDPoSChain/eth/tracers/native" _ "github.com/XinFinOrg/XDPoSChain/eth/tracers/native"
"gopkg.in/urfave/cli.v1"
) )
const ( const (
@ -51,7 +51,7 @@ var (
// Git SHA1 commit hash of the release (set via linker flags) // Git SHA1 commit hash of the release (set via linker flags)
gitCommit = "" gitCommit = ""
// The app that holds all commands and flags. // The app that holds all commands and flags.
app = utils.NewApp(gitCommit, "the XDPoSChain command line interface") app = flags.NewApp(gitCommit, "the XDPoSChain command line interface")
// flags that configure the node // flags that configure the node
nodeFlags = []cli.Flag{ nodeFlags = []cli.Flag{
utils.IdentityFlag, utils.IdentityFlag,
@ -98,14 +98,15 @@ var (
//utils.TrieCacheGenFlag, //utils.TrieCacheGenFlag,
utils.CacheLogSizeFlag, utils.CacheLogSizeFlag,
utils.FDLimitFlag, utils.FDLimitFlag,
utils.CryptoKZGFlag,
utils.ListenPortFlag, utils.ListenPortFlag,
utils.MaxPeersFlag, utils.MaxPeersFlag,
utils.MaxPendingPeersFlag, utils.MaxPendingPeersFlag,
utils.EtherbaseFlag, utils.MinerEtherbaseFlag,
utils.GasPriceFlag, utils.MinerGasPriceFlag,
utils.StakerThreadsFlag, utils.MinerThreadsFlag,
utils.StakingEnabledFlag, utils.MiningEnabledFlag,
utils.TargetGasLimitFlag, utils.MinerGasLimitFlag,
utils.NATFlag, utils.NATFlag,
utils.NoDiscoverFlag, utils.NoDiscoverFlag,
//utils.DiscoveryV5Flag, //utils.DiscoveryV5Flag,
@ -122,12 +123,9 @@ var (
utils.EnableXDCPrefixFlag, utils.EnableXDCPrefixFlag,
utils.RewoundFlag, utils.RewoundFlag,
utils.NetworkIdFlag, utils.NetworkIdFlag,
utils.RPCCORSDomainFlag, utils.HTTPCORSDomainFlag,
utils.RPCVirtualHostsFlag, utils.HTTPVirtualHostsFlag,
utils.EthStatsURLFlag, utils.EthStatsURLFlag,
utils.MetricsEnabledFlag,
utils.MetricsHTTPFlag,
utils.MetricsPortFlag,
//utils.FakePoWFlag, //utils.FakePoWFlag,
//utils.NoCompactionFlag, //utils.NoCompactionFlag,
//utils.GpoBlocksFlag, //utils.GpoBlocksFlag,
@ -136,6 +134,8 @@ var (
utils.GpoIgnoreGasPriceFlag, utils.GpoIgnoreGasPriceFlag,
//utils.ExtraDataFlag, //utils.ExtraDataFlag,
configFileFlag, configFileFlag,
utils.LogDebugFlag,
utils.LogBacktraceAtFlag,
utils.AnnounceTxsFlag, utils.AnnounceTxsFlag,
utils.StoreRewardFlag, utils.StoreRewardFlag,
utils.RollbackFlag, utils.RollbackFlag,
@ -143,12 +143,14 @@ var (
} }
rpcFlags = []cli.Flag{ rpcFlags = []cli.Flag{
utils.RPCEnabledFlag, utils.HTTPEnabledFlag,
utils.RPCGlobalGasCapFlag, utils.RPCGlobalGasCapFlag,
utils.RPCListenAddrFlag, utils.HTTPListenAddrFlag,
utils.RPCPortFlag, utils.HTTPPortFlag,
utils.RPCHttpWriteTimeoutFlag, utils.HTTPReadTimeoutFlag,
utils.RPCApiFlag, utils.HTTPWriteTimeoutFlag,
utils.HTTPIdleTimeoutFlag,
utils.HTTPApiFlag,
utils.WSEnabledFlag, utils.WSEnabledFlag,
utils.WSListenAddrFlag, utils.WSListenAddrFlag,
utils.WSPortFlag, utils.WSPortFlag,
@ -159,19 +161,29 @@ var (
utils.RPCGlobalTxFeeCap, utils.RPCGlobalTxFeeCap,
} }
whisperFlags = []cli.Flag{ metricsFlags = []cli.Flag{
utils.WhisperEnabledFlag, utils.MetricsEnabledFlag,
utils.WhisperMaxMessageSizeFlag, utils.MetricsEnabledExpensiveFlag,
utils.WhisperMinPOWFlag, utils.MetricsHTTPFlag,
utils.MetricsPortFlag,
utils.MetricsEnableInfluxDBFlag,
utils.MetricsInfluxDBEndpointFlag,
utils.MetricsInfluxDBDatabaseFlag,
utils.MetricsInfluxDBUsernameFlag,
utils.MetricsInfluxDBPasswordFlag,
utils.MetricsInfluxDBTagsFlag,
utils.MetricsEnableInfluxDBV2Flag,
utils.MetricsInfluxDBTokenFlag,
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
} }
) )
func init() { func init() {
// Initialize the CLI app and start XDC // Initialize the CLI app and start XDC
app.Action = XDC app.Action = XDC
app.HideVersion = true // we have a command to print the version app.Copyright = "Copyright (c) 2024 XDPoSChain"
app.Copyright = "Copyright (c) 2018 XDPoSChain" app.Commands = []*cli.Command{
app.Commands = []cli.Command{
// See chaincmd.go: // See chaincmd.go:
initCommand, initCommand,
importCommand, importCommand,
@ -196,13 +208,17 @@ func init() {
app.Flags = append(app.Flags, rpcFlags...) app.Flags = append(app.Flags, rpcFlags...)
app.Flags = append(app.Flags, consoleFlags...) app.Flags = append(app.Flags, consoleFlags...)
app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, debug.Flags...)
app.Flags = append(app.Flags, whisperFlags...) app.Flags = append(app.Flags, metricsFlags...)
flags.AutoEnvVars(app.Flags, "XDC")
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
flags.MigrateGlobalFlags(ctx)
if err := debug.Setup(ctx); err != nil { if err := debug.Setup(ctx); err != nil {
return err return err
} }
flags.CheckEnvVars(ctx, app.Flags, "XDC")
// Start system runtime metrics collection // Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second) go metrics.CollectProcessMetrics(3 * time.Second)
@ -229,6 +245,7 @@ func main() {
// blocking mode, waiting for it to be shut down. // blocking mode, waiting for it to be shut down.
func XDC(ctx *cli.Context) error { func XDC(ctx *cli.Context) error {
node, cfg := makeFullNode(ctx) node, cfg := makeFullNode(ctx)
defer node.Close()
startNode(ctx, node, cfg) startNode(ctx, node, cfg)
node.Wait() node.Wait()
return nil return nil
@ -244,11 +261,11 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
// Unlock any account specifically requested // Unlock any account specifically requested
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
if ctx.GlobalIsSet(utils.UnlockedAccountFlag.Name) { if ctx.IsSet(utils.UnlockedAccountFlag.Name) {
cfg.Account.Unlocks = strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") cfg.Account.Unlocks = strings.Split(ctx.String(utils.UnlockedAccountFlag.Name), ",")
} }
if ctx.GlobalIsSet(utils.PasswordFileFlag.Name) { if ctx.IsSet(utils.PasswordFileFlag.Name) {
cfg.Account.Passwords = utils.MakePasswordList(ctx) cfg.Account.Passwords = utils.MakePasswordList(ctx)
} }
@ -301,13 +318,9 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
// Start auxiliary services if enabled // Start auxiliary services if enabled
// Mining only makes sense if a full Ethereum node is running // Mining only makes sense if a full Ethereum node is running
if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { if ctx.Bool(utils.LightModeFlag.Name) || ctx.String(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support staking") utils.Fatalf("Light clients do not support staking")
} }
// Start metrics export if enabled
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
var ethereum *eth.Ethereum var ethereum *eth.Ethereum
if err := stack.Service(&ethereum); err != nil { if err := stack.Service(&ethereum); err != nil {
@ -317,7 +330,7 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
go func() { go func() {
started := false started := false
ok := false ok := false
slaveMode := ctx.GlobalIsSet(utils.XDCSlaveModeFlag.Name) slaveMode := ctx.IsSet(utils.XDCSlaveModeFlag.Name)
var err error var err error
ok, err = ethereum.ValidateMasternode() ok, err = ethereum.ValidateMasternode()
if err != nil { if err != nil {
@ -330,7 +343,7 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
} else { } else {
log.Info("Masternode found. Enabling staking mode...") log.Info("Masternode found. Enabling staking mode...")
// Use a reduced number of threads if requested // Use a reduced number of threads if requested
if threads := ctx.GlobalInt(utils.StakerThreadsFlag.Name); threads > 0 { if threads := ctx.Int(utils.MinerThreadsFlag.Name); threads > 0 {
type threaded interface { type threaded interface {
SetThreads(threads int) SetThreads(threads int)
} }
@ -372,7 +385,7 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
} else { } else {
log.Info("Masternode found. Enabling staking mode...") log.Info("Masternode found. Enabling staking mode...")
// Use a reduced number of threads if requested // Use a reduced number of threads if requested
if threads := ctx.GlobalInt(utils.StakerThreadsFlag.Name); threads > 0 { if threads := ctx.Int(utils.MinerThreadsFlag.Name); threads > 0 {
type threaded interface { type threaded interface {
SetThreads(threads int) SetThreads(threads int)
} }

View file

@ -28,16 +28,15 @@ import (
"github.com/XinFinOrg/XDPoSChain/eth" "github.com/XinFinOrg/XDPoSChain/eth"
"github.com/XinFinOrg/XDPoSChain/eth/ethconfig" "github.com/XinFinOrg/XDPoSChain/eth/ethconfig"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
makecacheCommand = cli.Command{ makecacheCommand = &cli.Command{
Action: utils.MigrateFlags(makecache), Action: makecache,
Name: "makecache", Name: "makecache",
Usage: "Generate ethash verification cache (for testing)", Usage: "Generate ethash verification cache (for testing)",
ArgsUsage: "<blockNum> <outputDir>", ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The makecache command generates an ethash cache in <outputDir>. The makecache command generates an ethash cache in <outputDir>.
@ -45,12 +44,11 @@ This command exists to support the system testing project.
Regular users do not need to execute it. Regular users do not need to execute it.
`, `,
} }
makedagCommand = cli.Command{ makedagCommand = &cli.Command{
Action: utils.MigrateFlags(makedag), Action: makedag,
Name: "makedag", Name: "makedag",
Usage: "Generate ethash mining DAG (for testing)", Usage: "Generate ethash mining DAG (for testing)",
ArgsUsage: "<blockNum> <outputDir>", ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The makedag command generates an ethash DAG in <outputDir>. The makedag command generates an ethash DAG in <outputDir>.
@ -58,28 +56,26 @@ This command exists to support the system testing project.
Regular users do not need to execute it. Regular users do not need to execute it.
`, `,
} }
versionCommand = cli.Command{ versionCommand = &cli.Command{
Action: utils.MigrateFlags(version), Action: version,
Name: "version", Name: "version",
Usage: "Print version numbers", Usage: "Print version numbers",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The output of this command is supposed to be machine-readable. The output of this command is supposed to be machine-readable.
`, `,
} }
licenseCommand = cli.Command{ licenseCommand = &cli.Command{
Action: utils.MigrateFlags(license), Action: license,
Name: "license", Name: "license",
Usage: "Display license information", Usage: "Display license information",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
} }
) )
// makecache generates an ethash verification cache into the provided folder. // makecache generates an ethash verification cache into the provided folder.
func makecache(ctx *cli.Context) error { func makecache(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args().Slice()
if len(args) != 2 { if len(args) != 2 {
utils.Fatalf(`Usage: XDC makecache <block number> <outputdir>`) utils.Fatalf(`Usage: XDC makecache <block number> <outputdir>`)
} }
@ -94,7 +90,7 @@ func makecache(ctx *cli.Context) error {
// makedag generates an ethash mining DAG into the provided folder. // makedag generates an ethash mining DAG into the provided folder.
func makedag(ctx *cli.Context) error { func makedag(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args().Slice()
if len(args) != 2 { if len(args) != 2 {
utils.Fatalf(`Usage: XDC makedag <block number> <outputdir>`) utils.Fatalf(`Usage: XDC makedag <block number> <outputdir>`)
} }

View file

@ -1,351 +0,0 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"math"
"reflect"
"runtime"
"sort"
"strings"
"time"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/node"
"github.com/XinFinOrg/XDPoSChain/rpc"
"github.com/gizak/termui"
"gopkg.in/urfave/cli.v1"
)
var (
monitorCommandAttachFlag = cli.StringFlag{
Name: "attach",
Value: node.DefaultIPCEndpoint(clientIdentifier),
Usage: "API endpoint to attach to",
}
monitorCommandRowsFlag = cli.IntFlag{
Name: "rows",
Value: 5,
Usage: "Maximum rows in the chart grid",
}
monitorCommandRefreshFlag = cli.IntFlag{
Name: "refresh",
Value: 3,
Usage: "Refresh interval in seconds",
}
monitorCommand = cli.Command{
Action: utils.MigrateFlags(monitor), // keep track of migration progress
Name: "monitor",
Usage: "Monitor and visualize node metrics",
ArgsUsage: " ",
Category: "MONITOR COMMANDS",
Description: `
The XDC monitor is a tool to collect and visualize various internal metrics
gathered by the node, supporting different chart types as well as the capacity
to display multiple metrics simultaneously.
`,
Flags: []cli.Flag{
monitorCommandAttachFlag,
monitorCommandRowsFlag,
monitorCommandRefreshFlag,
},
}
)
// monitor starts a terminal UI based monitoring tool for the requested metrics.
func monitor(ctx *cli.Context) error {
var (
client *rpc.Client
err error
)
// Attach to an Ethereum node over IPC or RPC
endpoint := ctx.String(monitorCommandAttachFlag.Name)
if client, err = dialRPC(endpoint); err != nil {
utils.Fatalf("Unable to attach to XDC node: %v", err)
}
defer client.Close()
// Retrieve all the available metrics and resolve the user pattens
metrics, err := retrieveMetrics(client)
if err != nil {
utils.Fatalf("Failed to retrieve system metrics: %v", err)
}
monitored := resolveMetrics(metrics, ctx.Args())
if len(monitored) == 0 {
list := expandMetrics(metrics, "")
sort.Strings(list)
if len(list) > 0 {
utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - "))
} else {
utils.Fatalf("No metrics collected by XDC (--%s).\n", utils.MetricsEnabledFlag.Name)
}
}
sort.Strings(monitored)
if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 {
utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - "))
}
// Create and configure the chart UI defaults
if err := termui.Init(); err != nil {
utils.Fatalf("Unable to initialize terminal UI: %v", err)
}
defer termui.Close()
rows := len(monitored)
if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max {
rows = max
}
cols := (len(monitored) + rows - 1) / rows
for i := 0; i < rows; i++ {
termui.Body.AddRows(termui.NewRow())
}
// Create each individual data chart
footer := termui.NewPar("")
footer.Block.Border = true
footer.Height = 3
charts := make([]*termui.LineChart, len(monitored))
units := make([]int, len(monitored))
data := make([][]float64, len(monitored))
for i := 0; i < len(monitored); i++ {
charts[i] = createChart((termui.TermHeight() - footer.Height) / rows)
row := termui.Body.Rows[i%rows]
row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i]))
}
termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer)))
refreshCharts(client, monitored, data, units, charts, ctx, footer)
termui.Body.Align()
termui.Render(termui.Body)
// Watch for various system events, and periodically refresh the charts
termui.Handle("/sys/kbd/C-c", func(termui.Event) {
termui.StopLoop()
})
termui.Handle("/sys/wnd/resize", func(termui.Event) {
termui.Body.Width = termui.TermWidth()
for _, chart := range charts {
chart.Height = (termui.TermHeight() - footer.Height) / rows
}
termui.Body.Align()
termui.Render(termui.Body)
})
go func() {
tick := time.NewTicker(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second)
for range tick.C {
if refreshCharts(client, monitored, data, units, charts, ctx, footer) {
termui.Body.Align()
}
termui.Render(termui.Body)
}
}()
termui.Loop()
return nil
}
// retrieveMetrics contacts the attached XDC node and retrieves the entire set
// of collected system metrics.
func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) {
var metrics map[string]interface{}
err := client.Call(&metrics, "debug_metrics", true)
return metrics, err
}
// resolveMetrics takes a list of input metric patterns, and resolves each to one
// or more canonical metric names.
func resolveMetrics(metrics map[string]interface{}, patterns []string) []string {
res := []string{}
for _, pattern := range patterns {
res = append(res, resolveMetric(metrics, pattern, "")...)
}
return res
}
// resolveMetrics takes a single of input metric pattern, and resolves it to one
// or more canonical metric names.
func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string {
results := []string{}
// If a nested metric was requested, recurse optionally branching (via comma)
parts := strings.SplitN(pattern, "/", 2)
if len(parts) > 1 {
for _, variation := range strings.Split(parts[0], ",") {
if submetrics, ok := metrics[variation].(map[string]interface{}); !ok {
utils.Fatalf("Failed to retrieve system metrics: %s", path+variation)
return nil
} else {
results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...)
}
}
return results
}
// Depending what the last link is, return or expand
for _, variation := range strings.Split(pattern, ",") {
switch metric := metrics[variation].(type) {
case float64:
// Final metric value found, return as singleton
results = append(results, path+variation)
case map[string]interface{}:
results = append(results, expandMetrics(metric, path+variation+"/")...)
default:
utils.Fatalf("Metric pattern resolved to unexpected type: %v", reflect.TypeOf(metric))
return nil
}
}
return results
}
// expandMetrics expands the entire tree of metrics into a flat list of paths.
func expandMetrics(metrics map[string]interface{}, path string) []string {
// Iterate over all fields and expand individually
list := []string{}
for name, metric := range metrics {
switch metric := metric.(type) {
case float64:
// Final metric value found, append to list
list = append(list, path+name)
case map[string]interface{}:
// Tree of metrics found, expand recursively
list = append(list, expandMetrics(metric, path+name+"/")...)
default:
utils.Fatalf("Metric pattern %s resolved to unexpected type: %v", path+name, reflect.TypeOf(metric))
return nil
}
}
return list
}
// fetchMetric iterates over the metrics map and retrieves a specific one.
func fetchMetric(metrics map[string]interface{}, metric string) float64 {
parts := strings.Split(metric, "/")
for _, part := range parts[:len(parts)-1] {
var found bool
metrics, found = metrics[part].(map[string]interface{})
if !found {
return 0
}
}
if v, ok := metrics[parts[len(parts)-1]].(float64); ok {
return v
}
return 0
}
// refreshCharts retrieves a next batch of metrics, and inserts all the new
// values into the active datasets and charts
func refreshCharts(client *rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
values, err := retrieveMetrics(client)
for i, metric := range metrics {
if len(data) < 512 {
data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...)
} else {
data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...)
}
if updateChart(metric, data[i], &units[i], charts[i], err) {
realign = true
}
}
updateFooter(ctx, err, footer)
return
}
// updateChart inserts a dataset into a line chart, scaling appropriately as to
// not display weird labels, also updating the chart label accordingly.
func updateChart(metric string, data []float64, base *int, chart *termui.LineChart, err error) (realign bool) {
dataUnits := []string{"", "K", "M", "G", "T", "E"}
timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"}
colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed}
// Extract only part of the data that's actually visible
if chart.Width*2 < len(data) {
data = data[:chart.Width*2]
}
// Find the maximum value and scale under 1K
high := 0.0
if len(data) > 0 {
high = data[0]
for _, value := range data[1:] {
high = math.Max(high, value)
}
}
unit, scale := 0, 1.0
for high >= 1000 && unit+1 < len(dataUnits) {
high, unit, scale = high/1000, unit+1, scale*1000
}
// If the unit changes, re-create the chart (hack to set max height...)
if unit != *base {
realign, *base, *chart = true, unit, *createChart(chart.Height)
}
// Update the chart's data points with the scaled values
if cap(chart.Data) < len(data) {
chart.Data = make([]float64, len(data))
}
chart.Data = chart.Data[:len(data)]
for i, value := range data {
chart.Data[i] = value / scale
}
// Update the chart's label with the scale units
units := dataUnits
if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") || strings.Contains(metric, "/time/") {
units = timeUnits
}
chart.BorderLabel = metric
if len(units[unit]) > 0 {
chart.BorderLabel += " [" + units[unit] + "]"
}
chart.LineColor = colors[unit] | termui.AttrBold
if err != nil {
chart.LineColor = termui.ColorRed | termui.AttrBold
}
return
}
// createChart creates an empty line chart with the default configs.
func createChart(height int) *termui.LineChart {
chart := termui.NewLineChart()
if runtime.GOOS == "windows" {
chart.Mode = "dot"
}
chart.DataLabels = []string{""}
chart.Height = height
chart.AxesColor = termui.ColorWhite
chart.PaddingBottom = -2
chart.BorderLabelFg = chart.BorderFg | termui.AttrBold
chart.BorderFg = chart.BorderBg
return chart
}
// updateFooter updates the footer contents based on any encountered errors.
func updateFooter(ctx *cli.Context, err error, footer *termui.Par) {
// Generate the basic footer
refresh := time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second
footer.Text = fmt.Sprintf("Press Ctrl+C to quit. Refresh interval: %v.", refresh)
footer.TextFgColor = termui.ThemeAttr("par.fg") | termui.AttrBold
// Append any encountered errors
if err != nil {
footer.Text = fmt.Sprintf("Error: %v.", err)
footer.TextFgColor = termui.ColorRed | termui.AttrBold
}
}

View file

@ -66,12 +66,12 @@ func runXDC(t *testing.T, args ...string) *testXDC {
tt := &testXDC{} tt := &testXDC{}
tt.TestCmd = cmdtest.NewTestCmd(t, tt) tt.TestCmd = cmdtest.NewTestCmd(t, tt)
for i, arg := range args { for i, arg := range args {
switch { switch arg {
case arg == "-datadir" || arg == "--datadir": case "--datadir":
if i < len(args)-1 { if i < len(args)-1 {
tt.Datadir = args[i+1] tt.Datadir = args[i+1]
} }
case arg == "-etherbase" || arg == "--etherbase": case "--miner-etherbase":
if i < len(args)-1 { if i < len(args)-1 {
tt.Etherbase = args[i+1] tt.Etherbase = args[i+1]
} }
@ -80,7 +80,7 @@ func runXDC(t *testing.T, args ...string) *testXDC {
if tt.Datadir == "" { if tt.Datadir == "" {
tt.Datadir = tmpdir(t) tt.Datadir = tmpdir(t)
tt.Cleanup = func() { os.RemoveAll(tt.Datadir) } tt.Cleanup = func() { os.RemoveAll(tt.Datadir) }
args = append([]string{"-datadir", tt.Datadir}, args...) args = append([]string{"--datadir", tt.Datadir}, args...)
// Remove the temporary datadir if something fails below. // Remove the temporary datadir if something fails below.
defer func() { defer func() {
if t.Failed() { if t.Failed() {

View file

@ -5,24 +5,24 @@ NAT = "" # flag --nat
[Eth] [Eth]
NetworkId = 89 # flag --networkid NetworkId = 89 # flag --networkid
SyncMode = "full" # flag --syncmode SyncMode = "full" # flag --syncmode
GasPrice = 1 # flag --gasprice GasPrice = 1 # flag --miner-gasprice
[Shh] [Shh]
[Node] [Node]
DataDir = "node1/" # flag --datadir DataDir = "node1/" # flag --datadir
HTTPPort = 8501 # flag --rpcport HTTPPort = 8501 # flag --http-port
HTTPHost = "localhost" # flags --rpcaddr & --rpc HTTPHost = "localhost" # flags --http-addr & --http
# in 3 cases : # in 3 cases :
# HTTPHost is "" == --rpc & --rpcaddr is not set # HTTPHost is "" == --http & --http-addr is not set
# HTTPHost is "localhost" or "127.0.0.1" == only set --rpc # HTTPHost is "localhost" or "127.0.0.1" == only set --http
# HTTPHost is other IP (ex : 192.168.1.1) = set 2 flags --rpc & --rpcaddr # HTTPHost is other IP (ex : 192.168.1.1) = set 2 flags --http & --http-addr
WSHost = "localhost" # flags --wsaddr & --ws . same option HTTPHost WSHost = "localhost" # flags --ws-addr & --ws . same option HTTPHost
WSPort = 8546 # flag --wsport WSPort = 8546 # flag --ws-port
WSModules = ["eth","ssh"] #flag --wsapi WSModules = ["eth","ssh"] #flag --ws-api
HTTPModules = ["personal","db","eth","net","web3","txpool","miner"] # flag --rpcapi HTTPModules = ["personal","db","eth","net","web3","txpool","miner"] # flag --http-api
KeyStoreDir = "" # flag --keystore KeyStoreDir = "" # flag --keystore
UserIdent = "" # flag --identity UserIdent = "" # flag --identity

View file

@ -1,331 +0,0 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Contains the XDC command usage template and generator.
package main
import (
"io"
"sort"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/internal/debug"
"gopkg.in/urfave/cli.v1"
)
// AppHelpTemplate is the test template for the default, global app help topic.
var AppHelpTemplate = `NAME:
{{.App.Name}} - {{.App.Usage}}
Copyright (c) 2018 XDPoSChain
USAGE:
{{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if .App.Version}}
VERSION:
{{.App.Version}}
{{end}}{{if len .App.Authors}}
AUTHOR(S):
{{range .App.Authors}}{{ . }}{{end}}
{{end}}{{if .App.Commands}}
COMMANDS:
{{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{end}}{{if .FlagGroups}}
{{range .FlagGroups}}{{.Name}} OPTIONS:
{{range .Flags}}{{.}}
{{end}}
{{end}}{{end}}{{if .App.Copyright }}
COPYRIGHT:
{{.App.Copyright}}
{{end}}
`
// flagGroup is a collection of flags belonging to a single topic.
type flagGroup struct {
Name string
Flags []cli.Flag
}
// AppHelpFlagGroups is the application flags, grouped by functionality.
var AppHelpFlagGroups = []flagGroup{
{
Name: "XDPoSChain",
Flags: []cli.Flag{
configFileFlag,
utils.DataDirFlag,
utils.KeyStoreDirFlag,
//utils.NoUSBFlag,
utils.NetworkIdFlag,
//utils.TestnetFlag,
//utils.RinkebyFlag,
utils.SyncModeFlag,
utils.GCModeFlag,
utils.EthStatsURLFlag,
utils.IdentityFlag,
//utils.LightServFlag,
//utils.LightPeersFlag,
//utils.LightKDFFlag,
},
},
//{Name: "DEVELOPER CHAIN",
// Flags: []cli.Flag{
// utils.DeveloperFlag,
// utils.DeveloperPeriodFlag,
// },
//},
//{
// Name: "ETHASH",
// Flags: []cli.Flag{
// utils.EthashCacheDirFlag,
// utils.EthashCachesInMemoryFlag,
// utils.EthashCachesOnDiskFlag,
// utils.EthashDatasetDirFlag,
// utils.EthashDatasetsInMemoryFlag,
// utils.EthashDatasetsOnDiskFlag,
// },
//},
//{
// Name: "DASHBOARD",
// Flags: []cli.Flag{
// utils.DashboardEnabledFlag,
// utils.DashboardAddrFlag,
// utils.DashboardPortFlag,
// utils.DashboardRefreshFlag,
// utils.DashboardAssetsFlag,
// },
//},
//{
// Name: "TRANSACTION POOL",
// Flags: []cli.Flag{
// utils.TxPoolNoLocalsFlag,
// utils.TxPoolJournalFlag,
// utils.TxPoolRejournalFlag,
// utils.TxPoolPriceLimitFlag,
// utils.TxPoolPriceBumpFlag,
// utils.TxPoolAccountSlotsFlag,
// utils.TxPoolGlobalSlotsFlag,
// utils.TxPoolAccountQueueFlag,
// utils.TxPoolGlobalQueueFlag,
// utils.TxPoolLifetimeFlag,
// },
//},
{
Name: "PERFORMANCE TUNING",
Flags: []cli.Flag{
utils.CacheFlag,
utils.CacheDatabaseFlag,
// utils.CacheGCFlag,
// utils.TrieCacheGenFlag,
utils.FDLimitFlag,
},
},
{
Name: "ACCOUNT",
Flags: []cli.Flag{
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
},
},
{
Name: "API AND CONSOLE",
Flags: []cli.Flag{
utils.RPCEnabledFlag,
utils.RPCGlobalGasCapFlag,
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RPCHttpWriteTimeoutFlag,
utils.RPCApiFlag,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,
utils.WSApiFlag,
utils.WSAllowedOriginsFlag,
utils.IPCDisabledFlag,
utils.IPCPathFlag,
utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.RPCGlobalTxFeeCap,
utils.JSpathFlag,
utils.ExecFlag,
utils.PreloadJSFlag,
},
},
{
Name: "NETWORKING",
Flags: []cli.Flag{
utils.BootnodesFlag,
utils.BootnodesV4Flag,
utils.BootnodesV5Flag,
utils.ListenPortFlag,
utils.MaxPeersFlag,
utils.MaxPendingPeersFlag,
utils.NATFlag,
utils.NoDiscoverFlag,
//utils.DiscoveryV5Flag,
//utils.NetrestrictFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
},
},
{
Name: "STAKER",
Flags: []cli.Flag{
utils.StakingEnabledFlag,
utils.StakerThreadsFlag,
utils.EtherbaseFlag,
utils.TargetGasLimitFlag,
utils.GasPriceFlag,
utils.ExtraDataFlag,
},
},
//{
// Name: "GAS PRICE ORACLE",
// Flags: []cli.Flag{
// utils.GpoBlocksFlag,
// utils.GpoPercentileFlag,
// utils.GpoMaxGasPriceFlag,
// utils.GpoIgnoreGasPriceFlag,
// },
//},
//{
// Name: "VIRTUAL MACHINE",
// Flags: []cli.Flag{
// utils.VMEnableDebugFlag,
// },
//},
{
Name: "LOGGING AND DEBUGGING",
Flags: append([]cli.Flag{
utils.MetricsEnabledFlag,
//utils.FakePoWFlag,
//utils.NoCompactionFlag,
}, debug.Flags...),
},
//{
// Name: "WHISPER (EXPERIMENTAL)",
// Flags: whisperFlags,
//},
{
Name: "DEPRECATED",
Flags: []cli.Flag{
utils.FastSyncFlag,
utils.LightModeFlag,
},
},
{
Name: "MISC",
},
}
// byCategory sorts an array of flagGroup by Name in the order
// defined in AppHelpFlagGroups.
type byCategory []flagGroup
func (a byCategory) Len() int { return len(a) }
func (a byCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byCategory) Less(i, j int) bool {
iCat, jCat := a[i].Name, a[j].Name
iIdx, jIdx := len(AppHelpFlagGroups), len(AppHelpFlagGroups) // ensure non categorized flags come last
for i, group := range AppHelpFlagGroups {
if iCat == group.Name {
iIdx = i
}
if jCat == group.Name {
jIdx = i
}
}
return iIdx < jIdx
}
func flagCategory(flag cli.Flag) string {
for _, category := range AppHelpFlagGroups {
for _, flg := range category.Flags {
if flg.GetName() == flag.GetName() {
return category.Name
}
}
}
return "MISC"
}
func init() {
// Override the default app help template
cli.AppHelpTemplate = AppHelpTemplate
// Define a one shot struct to pass to the usage template
type helpData struct {
App interface{}
FlagGroups []flagGroup
}
// Override the default app help printer, but only for the global app help
originalHelpPrinter := cli.HelpPrinter
cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) {
if tmpl == AppHelpTemplate {
// Iterate over all the flags and add any uncategorized ones
categorized := make(map[string]struct{})
for _, group := range AppHelpFlagGroups {
for _, flag := range group.Flags {
categorized[flag.String()] = struct{}{}
}
}
uncategorized := []cli.Flag{}
for _, flag := range data.(*cli.App).Flags {
if _, ok := categorized[flag.String()]; !ok {
uncategorized = append(uncategorized, flag)
}
}
if len(uncategorized) > 0 {
// Append all ungategorized options to the misc group
miscs := len(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags)
AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = append(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags, uncategorized...)
// Make sure they are removed afterwards
defer func() {
AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags[:miscs]
}()
}
// Render out custom usage screen
originalHelpPrinter(w, tmpl, helpData{data, AppHelpFlagGroups})
} else if tmpl == utils.CommandHelpTemplate {
// Iterate over all command specific flags and categorize them
categorized := make(map[string][]cli.Flag)
for _, flag := range data.(cli.Command).Flags {
if _, ok := categorized[flag.String()]; !ok {
categorized[flagCategory(flag)] = append(categorized[flagCategory(flag)], flag)
}
}
// sort to get a stable ordering
sorted := make([]flagGroup, 0, len(categorized))
for cat, flgs := range categorized {
sorted = append(sorted, flagGroup{cat, flgs})
}
sort.Sort(byCategory(sorted))
// add sorted array to data and render with default printer
originalHelpPrinter(w, tmpl, map[string]interface{}{
"cmd": data,
"categorizedFlags": sorted,
})
} else {
originalHelpPrinter(w, tmpl, data)
}
}
}

View file

@ -18,54 +18,101 @@ package main
import ( import (
"encoding/json" "encoding/json"
"flag"
"fmt" "fmt"
"os" "os"
"strings" "strings"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common/compiler" "github.com/XinFinOrg/XDPoSChain/common/compiler"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/urfave/cli/v2"
) )
var ( var (
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind") // Git SHA1 commit hash of the release (set via linker flags)
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)") gitCommit = ""
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind") app *cli.App
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
pkgFlag = flag.String("pkg", "", "Package name to generate the binding into")
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)")
) )
func main() { var (
// Parse and ensure all needed inputs are specified // Flags needed by abigen
flag.Parse() abiFlag = &cli.StringFlag{
Name: "abi",
Usage: "Path to the Ethereum contract ABI json to bind",
}
binFlag = &cli.StringFlag{
Name: "bin",
Usage: "Path to the Ethereum contract bytecode (generate deploy method)",
}
typeFlag = &cli.StringFlag{
Name: "type",
Usage: "Struct name for the binding (default = package name)",
}
solFlag = &cli.StringFlag{
Name: "sol",
Usage: "Path to the Ethereum contract Solidity source to build and bind",
}
solcFlag = &cli.StringFlag{
Name: "solc",
Usage: "Solidity compiler to use if source builds are requested",
Value: "solc",
}
excFlag = &cli.StringFlag{
Name: "exc",
Usage: "Comma separated types to exclude from binding",
}
pkgFlag = &cli.StringFlag{
Name: "pkg",
Usage: "Package name to generate the binding into",
}
outFlag = &cli.StringFlag{
Name: "out",
Usage: "Output file for the generated binding (default = stdout)",
}
langFlag = &cli.StringFlag{
Name: "lang",
Usage: "Destination language for the bindings (go)",
Value: "go",
}
)
if *abiFlag == "" && *solFlag == "" { func init() {
app = flags.NewApp(gitCommit, "ethereum checkpoint helper tool")
app.Name = "abigen"
app.Flags = []cli.Flag{
abiFlag,
binFlag,
typeFlag,
solFlag,
solcFlag,
excFlag,
pkgFlag,
outFlag,
langFlag,
}
app.Action = abigen
}
func abigen(c *cli.Context) error {
if c.String(abiFlag.Name) == "" && c.String(solFlag.Name) == "" {
fmt.Printf("No contract ABI (--abi) or Solidity source (--sol) specified\n") fmt.Printf("No contract ABI (--abi) or Solidity source (--sol) specified\n")
os.Exit(-1) os.Exit(-1)
} else if (*abiFlag != "" || *binFlag != "" || *typFlag != "") && *solFlag != "" { } else if (c.String(abiFlag.Name) != "" || c.String(binFlag.Name) != "" || c.String(typeFlag.Name) != "") && c.String(solFlag.Name) != "" {
fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity source (--sol) flag\n") fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity source (--sol) flag\n")
os.Exit(-1) os.Exit(-1)
} }
if *pkgFlag == "" { if c.String(pkgFlag.Name) == "" {
fmt.Printf("No destination package specified (--pkg)\n") fmt.Printf("No destination package specified (--pkg)\n")
os.Exit(-1) os.Exit(-1)
} }
var lang bind.Lang var lang bind.Lang
switch *langFlag { switch c.String(langFlag.Name) {
case "go": case "go":
lang = bind.LangGo lang = bind.LangGo
case "java":
lang = bind.LangJava
case "objc":
lang = bind.LangObjC
default: default:
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag) fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", c.String(langFlag.Name))
os.Exit(-1) os.Exit(-1)
} }
// If the entire solidity code was specified, build and bind based on that // If the entire solidity code was specified, build and bind based on that
@ -74,13 +121,13 @@ func main() {
bins []string bins []string
types []string types []string
) )
if *solFlag != "" { if c.String(solFlag.Name) != "" {
// Generate the list of types to exclude from binding // Generate the list of types to exclude from binding
exclude := make(map[string]bool) exclude := make(map[string]bool)
for _, kind := range strings.Split(*excFlag, ",") { for _, kind := range strings.Split(c.String(excFlag.Name), ",") {
exclude[strings.ToLower(kind)] = true exclude[strings.ToLower(kind)] = true
} }
contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag) contracts, err := compiler.CompileSolidity(c.String(solcFlag.Name), c.String(solFlag.Name))
if err != nil { if err != nil {
fmt.Printf("Failed to build Solidity contract: %v\n", err) fmt.Printf("Failed to build Solidity contract: %v\n", err)
os.Exit(-1) os.Exit(-1)
@ -99,7 +146,7 @@ func main() {
} }
} else { } else {
// Otherwise load up the ABI, optional bytecode and type name from the parameters // Otherwise load up the ABI, optional bytecode and type name from the parameters
abi, err := os.ReadFile(*abiFlag) abi, err := os.ReadFile(c.String(abiFlag.Name))
if err != nil { if err != nil {
fmt.Printf("Failed to read input ABI: %v\n", err) fmt.Printf("Failed to read input ABI: %v\n", err)
os.Exit(-1) os.Exit(-1)
@ -107,33 +154,43 @@ func main() {
abis = append(abis, string(abi)) abis = append(abis, string(abi))
bin := []byte{} bin := []byte{}
if *binFlag != "" { if c.String(binFlag.Name) != "" {
if bin, err = os.ReadFile(*binFlag); err != nil { if bin, err = os.ReadFile(c.String(binFlag.Name)); err != nil {
fmt.Printf("Failed to read input bytecode: %v\n", err) fmt.Printf("Failed to read input bytecode: %v\n", err)
os.Exit(-1) os.Exit(-1)
} }
} }
bins = append(bins, string(bin)) bins = append(bins, string(bin))
kind := *typFlag kind := c.String(typeFlag.Name)
if kind == "" { if kind == "" {
kind = *pkgFlag kind = c.String(pkgFlag.Name)
} }
types = append(types, kind) types = append(types, kind)
} }
// Generate the contract binding // Generate the contract binding
code, err := bind.Bind(types, abis, bins, *pkgFlag, lang) code, err := bind.Bind(types, abis, bins, c.String(pkgFlag.Name), lang)
if err != nil { if err != nil {
fmt.Printf("Failed to generate ABI binding: %v\n", err) fmt.Printf("Failed to generate ABI binding: %v\n", err)
os.Exit(-1) os.Exit(-1)
} }
// Either flush it out to a file or display on the standard output // Either flush it out to a file or display on the standard output
if *outFlag == "" { if c.String(outFlag.Name) == "" {
fmt.Printf("%s\n", code) fmt.Printf("%s\n", code)
return return nil
} }
if err := os.WriteFile(*outFlag, []byte(code), 0600); err != nil { if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil {
fmt.Printf("Failed to write ABI binding: %v\n", err) fmt.Printf("Failed to write ABI binding: %v\n", err)
os.Exit(-1) os.Exit(-1)
} }
return nil
}
func main() {
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} }

View file

@ -51,10 +51,10 @@ func main() {
) )
flag.Parse() flag.Parse()
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.Lvl(*verbosity)) glogger.Verbosity(log.FromLegacyLevel(*verbosity))
glogger.Vmodule(*vmodule) glogger.Vmodule(*vmodule)
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
natm, err := nat.Parse(*natdesc) natm, err := nat.Parse(*natdesc)
if err != nil { if err != nil {

View file

@ -26,7 +26,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/pborman/uuid" "github.com/pborman/uuid"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputGenerate struct { type outputGenerate struct {
@ -34,7 +34,14 @@ type outputGenerate struct {
AddressEIP55 string AddressEIP55 string
} }
var commandGenerate = cli.Command{ var (
privateKeyFlag = &cli.StringFlag{
Name: "privatekey",
Usage: "file containing a raw private key to encrypt",
}
)
var commandGenerate = &cli.Command{
Name: "generate", Name: "generate",
Usage: "generate new keyfile", Usage: "generate new keyfile",
ArgsUsage: "[ <keyfile> ]", ArgsUsage: "[ <keyfile> ]",
@ -47,10 +54,7 @@ If you want to encrypt an existing private key, it can be specified by setting
Flags: []cli.Flag{ Flags: []cli.Flag{
passphraseFlag, passphraseFlag,
jsonFlag, jsonFlag,
cli.StringFlag{ privateKeyFlag,
Name: "privatekey",
Usage: "file containing a raw private key to encrypt",
},
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
// Check if keyfile path given and make sure it doesn't already exist. // Check if keyfile path given and make sure it doesn't already exist.

View file

@ -24,7 +24,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts/keystore" "github.com/XinFinOrg/XDPoSChain/accounts/keystore"
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputInspect struct { type outputInspect struct {
@ -33,7 +33,14 @@ type outputInspect struct {
PrivateKey string PrivateKey string
} }
var commandInspect = cli.Command{ var (
privateFlag = &cli.BoolFlag{
Name: "private",
Usage: "include the private key in the output",
}
)
var commandInspect = &cli.Command{
Name: "inspect", Name: "inspect",
Usage: "inspect a keyfile", Usage: "inspect a keyfile",
ArgsUsage: "<keyfile>", ArgsUsage: "<keyfile>",
@ -45,10 +52,7 @@ make sure to use this feature with great caution!`,
Flags: []cli.Flag{ Flags: []cli.Flag{
passphraseFlag, passphraseFlag,
jsonFlag, jsonFlag,
cli.BoolFlag{ privateFlag,
Name: "private",
Usage: "include the private key in the output",
},
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
keyfilepath := ctx.Args().First() keyfilepath := ctx.Args().First()

View file

@ -20,8 +20,8 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/internal/flags"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (
@ -34,8 +34,8 @@ var gitCommit = ""
var app *cli.App var app *cli.App
func init() { func init() {
app = utils.NewApp(gitCommit, "an Ethereum key manager") app = flags.NewApp(gitCommit, "an Ethereum key manager")
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
commandGenerate, commandGenerate,
commandInspect, commandInspect,
commandSignMessage, commandSignMessage,
@ -45,15 +45,15 @@ func init() {
// Commonly used command line flags. // Commonly used command line flags.
var ( var (
passphraseFlag = cli.StringFlag{ passphraseFlag = &cli.StringFlag{
Name: "passwordfile", Name: "passwordfile",
Usage: "the file that contains the passphrase for the keyfile", Usage: "the file that contains the password for the keyfile",
} }
jsonFlag = cli.BoolFlag{ jsonFlag = &cli.BoolFlag{
Name: "json", Name: "json",
Usage: "output JSON instead of human-readable format", Usage: "output JSON instead of human-readable format",
} }
messageFlag = cli.StringFlag{ messageFlag = &cli.StringFlag{
Name: "message", Name: "message",
Usage: "the file that contains the message to sign/verify", Usage: "the file that contains the message to sign/verify",
} }

View file

@ -25,19 +25,19 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputSign struct { type outputSign struct {
Signature string Signature string
} }
var msgfileFlag = cli.StringFlag{ var msgfileFlag = &cli.StringFlag{
Name: "msgfile", Name: "msgfile",
Usage: "file containing the message to sign/verify", Usage: "file containing the message to sign/verify",
} }
var commandSignMessage = cli.Command{ var commandSignMessage = &cli.Command{
Name: "signmessage", Name: "signmessage",
Usage: "sign a message", Usage: "sign a message",
ArgsUsage: "<keyfile> <message>", ArgsUsage: "<keyfile> <message>",
@ -88,7 +88,7 @@ type outputVerify struct {
RecoveredPublicKey string RecoveredPublicKey string
} }
var commandVerifyMessage = cli.Command{ var commandVerifyMessage = &cli.Command{
Name: "verifymessage", Name: "verifymessage",
Usage: "verify the signature of a signed message", Usage: "verify the signature of a signed message",
ArgsUsage: "<address> <signature> <message>", ArgsUsage: "<address> <signature> <message>",
@ -143,7 +143,7 @@ It is possible to refer to a file containing the message.`,
func getMessage(ctx *cli.Context, msgarg int) []byte { func getMessage(ctx *cli.Context, msgarg int) []byte {
if file := ctx.String("msgfile"); file != "" { if file := ctx.String("msgfile"); file != "" {
if len(ctx.Args()) > msgarg { if ctx.NArg() > msgarg {
utils.Fatalf("Can't use --msgfile and message argument at the same time.") utils.Fatalf("Can't use --msgfile and message argument at the same time.")
} }
msg, err := os.ReadFile(file) msg, err := os.ReadFile(file)
@ -151,9 +151,9 @@ func getMessage(ctx *cli.Context, msgarg int) []byte {
utils.Fatalf("Can't read message file: %v", err) utils.Fatalf("Can't read message file: %v", err)
} }
return msg return msg
} else if len(ctx.Args()) == msgarg+1 { } else if ctx.NArg() == msgarg+1 {
return []byte(ctx.Args().Get(msgarg)) return []byte(ctx.Args().Get(msgarg))
} }
utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, ctx.NArg())
return nil return nil
} }

View file

@ -25,7 +25,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/console" "github.com/XinFinOrg/XDPoSChain/console"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
// getPassPhrase obtains a passphrase given by the user. It first checks the // getPassPhrase obtains a passphrase given by the user. It first checks the

View file

@ -22,11 +22,10 @@ import (
"os" "os"
"github.com/XinFinOrg/XDPoSChain/cmd/evm/internal/compiler" "github.com/XinFinOrg/XDPoSChain/cmd/evm/internal/compiler"
"github.com/urfave/cli/v2"
cli "gopkg.in/urfave/cli.v1"
) )
var compileCommand = cli.Command{ var compileCommand = &cli.Command{
Action: compileCmd, Action: compileCmd,
Name: "compile", Name: "compile",
Usage: "compiles easm source to evm binary", Usage: "compiles easm source to evm binary",
@ -34,7 +33,7 @@ var compileCommand = cli.Command{
} }
func compileCmd(ctx *cli.Context) error { func compileCmd(ctx *cli.Context) error {
debug := ctx.GlobalBool(DebugFlag.Name) debug := ctx.Bool(DebugFlag.Name)
if len(ctx.Args().First()) == 0 { if len(ctx.Args().First()) == 0 {
return errors.New("filename required") return errors.New("filename required")

View file

@ -23,10 +23,10 @@ import (
"strings" "strings"
"github.com/XinFinOrg/XDPoSChain/core/asm" "github.com/XinFinOrg/XDPoSChain/core/asm"
cli "gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var disasmCommand = cli.Command{ var disasmCommand = &cli.Command{
Action: disasmCmd, Action: disasmCmd,
Name: "disasm", Name: "disasm",
Usage: "disassembles evm binary", Usage: "disassembles evm binary",
@ -34,17 +34,22 @@ var disasmCommand = cli.Command{
} }
func disasmCmd(ctx *cli.Context) error { func disasmCmd(ctx *cli.Context) error {
if len(ctx.Args().First()) == 0 { var in string
return errors.New("filename required") switch {
case len(ctx.Args().First()) > 0:
fn := ctx.Args().First()
input, err := os.ReadFile(fn)
if err != nil {
return err
}
in = string(input)
case ctx.IsSet(InputFlag.Name):
in = ctx.String(InputFlag.Name)
default:
return errors.New("missing filename or --input value")
} }
fn := ctx.Args().First() code := strings.TrimSpace(in)
in, err := os.ReadFile(fn)
if err != nil {
return err
}
code := strings.TrimSpace(string(in[:]))
fmt.Printf("%v\n", code) fmt.Printf("%v\n", code)
return asm.PrintDisassembled(code) return asm.PrintDisassembled(code)
} }

View file

@ -22,93 +22,126 @@ import (
"math/big" "math/big"
"os" "os"
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/internal/flags"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) var (
gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
app = flags.NewApp(gitCommit, "the evm command line interface")
)
var ( var (
app = utils.NewApp(gitCommit, "the evm command line interface") DebugFlag = &cli.BoolFlag{
Name: "debug",
DebugFlag = cli.BoolFlag{ Usage: "output full trace logs",
Name: "debug", Category: flags.VMCategory,
Usage: "output full trace logs",
} }
MemProfileFlag = cli.StringFlag{ MemProfileFlag = &cli.StringFlag{
Name: "memprofile", Name: "memprofile",
Usage: "creates a memory profile at the given path", Usage: "creates a memory profile at the given path",
Category: flags.VMCategory,
} }
CPUProfileFlag = cli.StringFlag{ CPUProfileFlag = &cli.StringFlag{
Name: "cpuprofile", Name: "cpuprofile",
Usage: "creates a CPU profile at the given path", Usage: "creates a CPU profile at the given path",
Category: flags.VMCategory,
} }
StatDumpFlag = cli.BoolFlag{ StatDumpFlag = &cli.BoolFlag{
Name: "statdump", Name: "statdump",
Usage: "displays stack and heap memory information", Usage: "displays stack and heap memory information",
Category: flags.VMCategory,
} }
CodeFlag = cli.StringFlag{ CodeFlag = &cli.StringFlag{
Name: "code", Name: "code",
Usage: "EVM code", Usage: "EVM code",
Category: flags.VMCategory,
} }
CodeFileFlag = cli.StringFlag{ CodeFileFlag = &cli.StringFlag{
Name: "codefile", Name: "codefile",
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
Category: flags.VMCategory,
} }
GasFlag = cli.Uint64Flag{ GasFlag = &cli.Uint64Flag{
Name: "gas", Name: "gas",
Usage: "gas limit for the evm", Usage: "gas limit for the evm",
Value: 10000000000, Value: 10000000000,
Category: flags.VMCategory,
} }
PriceFlag = utils.BigFlag{ PriceFlag = &flags.BigFlag{
Name: "price", Name: "price",
Usage: "price set for the evm", Usage: "price set for the evm",
Value: new(big.Int), Value: new(big.Int),
Category: flags.VMCategory,
} }
ValueFlag = utils.BigFlag{ ValueFlag = &flags.BigFlag{
Name: "value", Name: "value",
Usage: "value set for the evm", Usage: "value set for the evm",
Value: new(big.Int), Value: new(big.Int),
Category: flags.VMCategory,
} }
DumpFlag = cli.BoolFlag{ DumpFlag = &cli.BoolFlag{
Name: "dump", Name: "dump",
Usage: "dumps the state after the run", Usage: "dumps the state after the run",
Category: flags.VMCategory,
} }
InputFlag = cli.StringFlag{ InputFlag = &cli.StringFlag{
Name: "input", Name: "input",
Usage: "input for the EVM", Usage: "input for the EVM",
Category: flags.VMCategory,
} }
VerbosityFlag = cli.IntFlag{ VerbosityFlag = &cli.IntFlag{
Name: "verbosity", Name: "verbosity",
Usage: "sets the verbosity level", Usage: "sets the verbosity level",
Category: flags.VMCategory,
} }
CreateFlag = cli.BoolFlag{ CreateFlag = &cli.BoolFlag{
Name: "create", Name: "create",
Usage: "indicates the action should be create rather than call", Usage: "indicates the action should be create rather than call",
Category: flags.VMCategory,
} }
GenesisFlag = cli.StringFlag{ GenesisFlag = &cli.StringFlag{
Name: "prestate", Name: "prestate",
Usage: "JSON file with prestate (genesis) config", Usage: "JSON file with prestate (genesis) config",
Category: flags.VMCategory,
} }
MachineFlag = cli.BoolFlag{ MachineFlag = &cli.BoolFlag{
Name: "json", Name: "json",
Usage: "output trace logs in machine readable format (json)", Usage: "output trace logs in machine readable format (json)",
Category: flags.VMCategory,
} }
SenderFlag = cli.StringFlag{ SenderFlag = &cli.StringFlag{
Name: "sender", Name: "sender",
Usage: "The transaction origin", Usage: "The transaction origin",
Category: flags.VMCategory,
} }
ReceiverFlag = cli.StringFlag{ ReceiverFlag = &cli.StringFlag{
Name: "receiver", Name: "receiver",
Usage: "The transaction receiver (execution context)", Usage: "The transaction receiver (execution context)",
Category: flags.VMCategory,
} }
DisableMemoryFlag = cli.BoolFlag{ DisableMemoryFlag = &cli.BoolFlag{
Name: "nomemory", Name: "nomemory",
Usage: "disable memory output", Value: true,
Usage: "disable memory output",
Category: flags.VMCategory,
} }
DisableStackFlag = cli.BoolFlag{ DisableStackFlag = &cli.BoolFlag{
Name: "nostack", Name: "nostack",
Usage: "disable stack output", Usage: "disable stack output",
Category: flags.VMCategory,
}
DisableStorageFlag = &cli.BoolFlag{
Name: "nostorage",
Usage: "disable storage output",
Category: flags.VMCategory,
}
DisableReturnDataFlag = &cli.BoolFlag{
Name: "noreturndata",
Value: true,
Usage: "enable return data output",
Category: flags.VMCategory,
} }
) )
@ -134,7 +167,7 @@ func init() {
DisableMemoryFlag, DisableMemoryFlag,
DisableStackFlag, DisableStackFlag,
} }
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
compileCommand, compileCommand,
disasmCommand, disasmCommand,
runCommand, runCommand,

View file

@ -22,26 +22,24 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
goruntime "runtime"
"runtime/pprof" "runtime/pprof"
"time" "time"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
goruntime "runtime"
"github.com/XinFinOrg/XDPoSChain/cmd/evm/internal/compiler" "github.com/XinFinOrg/XDPoSChain/cmd/evm/internal/compiler"
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/core/vm/runtime" "github.com/XinFinOrg/XDPoSChain/core/vm/runtime"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
cli "gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var runCommand = cli.Command{ var runCommand = &cli.Command{
Action: runCmd, Action: runCmd,
Name: "run", Name: "run",
Usage: "run arbitrary evm binary", Usage: "run arbitrary evm binary",
@ -71,12 +69,12 @@ func readGenesis(genesisPath string) *core.Genesis {
} }
func runCmd(ctx *cli.Context) error { func runCmd(ctx *cli.Context) error {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
log.Root().SetHandler(glogger)
logconfig := &vm.LogConfig{ logconfig := &vm.LogConfig{
EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name), DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
Debug: ctx.Bool(DebugFlag.Name),
} }
var ( var (
@ -87,16 +85,17 @@ func runCmd(ctx *cli.Context) error {
sender = common.StringToAddress("sender") sender = common.StringToAddress("sender")
receiver = common.StringToAddress("receiver") receiver = common.StringToAddress("receiver")
) )
if ctx.GlobalBool(MachineFlag.Name) { if ctx.Bool(MachineFlag.Name) {
tracer = vm.NewJSONLogger(logconfig, os.Stdout) tracer = vm.NewJSONLogger(logconfig, os.Stdout)
} else if ctx.GlobalBool(DebugFlag.Name) { } else if ctx.Bool(DebugFlag.Name) {
debugLogger = vm.NewStructLogger(logconfig) debugLogger = vm.NewStructLogger(logconfig)
tracer = debugLogger tracer = debugLogger
} else { } else {
debugLogger = vm.NewStructLogger(logconfig) debugLogger = vm.NewStructLogger(logconfig)
} }
if ctx.GlobalString(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) if ctx.String(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.String(GenesisFlag.Name))
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
genesis := gen.ToBlock(db) genesis := gen.ToBlock(db)
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
@ -105,13 +104,13 @@ func runCmd(ctx *cli.Context) error {
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) statedb, _ = state.New(common.Hash{}, state.NewDatabase(db))
} }
if ctx.GlobalString(SenderFlag.Name) != "" { if ctx.String(SenderFlag.Name) != "" {
sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) sender = common.HexToAddress(ctx.String(SenderFlag.Name))
} }
statedb.CreateAccount(sender) statedb.CreateAccount(sender)
if ctx.GlobalString(ReceiverFlag.Name) != "" { if ctx.String(ReceiverFlag.Name) != "" {
receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name))
} }
var ( var (
@ -120,11 +119,11 @@ func runCmd(ctx *cli.Context) error {
err error err error
) )
// The '--code' or '--codefile' flag overrides code in state // The '--code' or '--codefile' flag overrides code in state
if ctx.GlobalString(CodeFileFlag.Name) != "" { if ctx.String(CodeFileFlag.Name) != "" {
var hexcode []byte var hexcode []byte
var err error var err error
// If - is specified, it means that code comes from stdin // If - is specified, it means that code comes from stdin
if ctx.GlobalString(CodeFileFlag.Name) == "-" { if ctx.String(CodeFileFlag.Name) == "-" {
//Try reading from stdin //Try reading from stdin
if hexcode, err = io.ReadAll(os.Stdin); err != nil { if hexcode, err = io.ReadAll(os.Stdin); err != nil {
fmt.Printf("Could not load code from stdin: %v\n", err) fmt.Printf("Could not load code from stdin: %v\n", err)
@ -132,15 +131,15 @@ func runCmd(ctx *cli.Context) error {
} }
} else { } else {
// Codefile with hex assembly // Codefile with hex assembly
if hexcode, err = os.ReadFile(ctx.GlobalString(CodeFileFlag.Name)); err != nil { if hexcode, err = os.ReadFile(ctx.String(CodeFileFlag.Name)); err != nil {
fmt.Printf("Could not load code from file: %v\n", err) fmt.Printf("Could not load code from file: %v\n", err)
os.Exit(1) os.Exit(1)
} }
} }
code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n")))
} else if ctx.GlobalString(CodeFlag.Name) != "" { } else if ctx.String(CodeFlag.Name) != "" {
code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) code = common.Hex2Bytes(ctx.String(CodeFlag.Name))
} else if fn := ctx.Args().First(); len(fn) > 0 { } else if fn := ctx.Args().First(); len(fn) > 0 {
// EASM-file to compile // EASM-file to compile
src, err := os.ReadFile(fn) src, err := os.ReadFile(fn)
@ -154,20 +153,20 @@ func runCmd(ctx *cli.Context) error {
code = common.Hex2Bytes(bin) code = common.Hex2Bytes(bin)
} }
initialGas := ctx.GlobalUint64(GasFlag.Name) initialGas := ctx.Uint64(GasFlag.Name)
runtimeConfig := runtime.Config{ runtimeConfig := runtime.Config{
Origin: sender, Origin: sender,
State: statedb, State: statedb,
GasLimit: initialGas, GasLimit: initialGas,
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), GasPrice: flags.GlobalBig(ctx, PriceFlag.Name),
Value: utils.GlobalBig(ctx, ValueFlag.Name), Value: flags.GlobalBig(ctx, ValueFlag.Name),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
}, },
} }
if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" {
f, err := os.Create(cpuProfilePath) f, err := os.Create(cpuProfilePath)
if err != nil { if err != nil {
fmt.Println("could not create CPU profile: ", err) fmt.Println("could not create CPU profile: ", err)
@ -185,23 +184,23 @@ func runCmd(ctx *cli.Context) error {
} }
tstart := time.Now() tstart := time.Now()
var leftOverGas uint64 var leftOverGas uint64
if ctx.GlobalBool(CreateFlag.Name) { if ctx.Bool(CreateFlag.Name) {
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) input := append(code, common.Hex2Bytes(ctx.String(InputFlag.Name))...)
ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig) ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig)
} else { } else {
if len(code) > 0 { if len(code) > 0 {
statedb.SetCode(receiver, code) statedb.SetCode(receiver, code)
} }
ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig) ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.String(InputFlag.Name)), &runtimeConfig)
} }
execTime := time.Since(tstart) execTime := time.Since(tstart)
if ctx.GlobalBool(DumpFlag.Name) { if ctx.Bool(DumpFlag.Name) {
statedb.IntermediateRoot(true) statedb.IntermediateRoot(true)
fmt.Println(string(statedb.Dump())) fmt.Println(string(statedb.Dump()))
} }
if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" {
f, err := os.Create(memProfilePath) f, err := os.Create(memProfilePath)
if err != nil { if err != nil {
fmt.Println("could not create memory profile: ", err) fmt.Println("could not create memory profile: ", err)
@ -214,7 +213,7 @@ func runCmd(ctx *cli.Context) error {
f.Close() f.Close()
} }
if ctx.GlobalBool(DebugFlag.Name) { if ctx.Bool(DebugFlag.Name) {
if debugLogger != nil { if debugLogger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####") fmt.Fprintln(os.Stderr, "#### TRACE ####")
vm.WriteTrace(os.Stderr, debugLogger.StructLogs()) vm.WriteTrace(os.Stderr, debugLogger.StructLogs())
@ -223,7 +222,7 @@ func runCmd(ctx *cli.Context) error {
vm.WriteLogs(os.Stderr, statedb.Logs()) vm.WriteLogs(os.Stderr, statedb.Logs())
} }
if ctx.GlobalBool(StatDumpFlag.Name) { if ctx.Bool(StatDumpFlag.Name) {
var mem goruntime.MemStats var mem goruntime.MemStats
goruntime.ReadMemStats(&mem) goruntime.ReadMemStats(&mem)
fmt.Fprintf(os.Stderr, `evm execution time: %v fmt.Fprintf(os.Stderr, `evm execution time: %v
@ -238,7 +237,7 @@ Gas used: %d
if tracer != nil { if tracer != nil {
tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err)
} else { } else {
fmt.Printf("0x%x\n", ret) fmt.Printf("%#x\n", ret)
if err != nil { if err != nil {
fmt.Printf(" error: %v\n", err) fmt.Printf(" error: %v\n", err)
} }

View file

@ -24,13 +24,11 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/tests" "github.com/XinFinOrg/XDPoSChain/tests"
"github.com/urfave/cli/v2"
cli "gopkg.in/urfave/cli.v1"
) )
var stateTestCommand = cli.Command{ var stateTestCommand = &cli.Command{
Action: stateTestCmd, Action: stateTestCmd,
Name: "statetest", Name: "statetest",
Usage: "executes the given state tests", Usage: "executes the given state tests",
@ -49,25 +47,24 @@ func stateTestCmd(ctx *cli.Context) error {
if len(ctx.Args().First()) == 0 { if len(ctx.Args().First()) == 0 {
return errors.New("path-to-test argument required") return errors.New("path-to-test argument required")
} }
// Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
log.Root().SetHandler(glogger)
// Configure the EVM logger // Configure the EVM logger
config := &vm.LogConfig{ config := &vm.LogConfig{
EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name), DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
} }
var ( var (
tracer vm.EVMLogger tracer vm.EVMLogger
debugger *vm.StructLogger debugger *vm.StructLogger
) )
switch { switch {
case ctx.GlobalBool(MachineFlag.Name): case ctx.Bool(MachineFlag.Name):
tracer = vm.NewJSONLogger(config, os.Stderr) tracer = vm.NewJSONLogger(config, os.Stderr)
case ctx.GlobalBool(DebugFlag.Name): case ctx.Bool(DebugFlag.Name):
debugger = vm.NewStructLogger(config) debugger = vm.NewStructLogger(config)
tracer = debugger tracer = debugger
@ -86,7 +83,7 @@ func stateTestCmd(ctx *cli.Context) error {
// Iterate over all the tests, run them and aggregate the results // Iterate over all the tests, run them and aggregate the results
cfg := vm.Config{ cfg := vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
} }
results := make([]StatetestResult, 0, len(tests)) results := make([]StatetestResult, 0, len(tests))
for key, test := range tests { for key, test := range tests {
@ -97,20 +94,20 @@ func stateTestCmd(ctx *cli.Context) error {
if err != nil { if err != nil {
// Test failed, mark as so and dump any state to aid debugging // Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error() result.Pass, result.Error = false, err.Error()
if ctx.GlobalBool(DumpFlag.Name) && state != nil { if ctx.Bool(DumpFlag.Name) && state != nil {
dump := state.RawDump() dump := state.RawDump()
result.State = &dump result.State = &dump
} }
} }
// print state root for evmlab tracing (already committed above, so no need to delete objects again // print state root for evmlab tracing (already committed above, so no need to delete objects again
if ctx.GlobalBool(MachineFlag.Name) && state != nil { if ctx.Bool(MachineFlag.Name) && state != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false))
} }
results = append(results, *result) results = append(results, *result)
// Print any structured logs collected // Print any structured logs collected
if ctx.GlobalBool(DebugFlag.Name) { if ctx.Bool(DebugFlag.Name) {
if debugger != nil { if debugger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####") fmt.Fprintln(os.Stderr, "#### TRACE ####")
vm.WriteTrace(os.Stderr, debugger.StructLogs()) vm.WriteTrace(os.Stderr, debugger.StructLogs())

View file

@ -94,7 +94,7 @@ var (
func main() { func main() {
// Parse the flags and set up the logger to print everything requested // Parse the flags and set up the logger to print everything requested
flag.Parse() flag.Parse()
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*logFlag), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.FromLegacyLevel(*logFlag), true)))
// Construct the payout tiers // Construct the payout tiers
amounts := make([]string, *tiersFlag) amounts := make([]string, *tiersFlag)
@ -287,7 +287,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
// close terminates the Ethereum connection and tears down the faucet. // close terminates the Ethereum connection and tears down the faucet.
func (f *faucet) close() error { func (f *faucet) close() error {
return f.stack.Stop() return f.stack.Close()
} }
// listenAndServe registers the HTTP handlers for the faucet and boots it up // listenAndServe registers the HTTP handlers for the faucet and boots it up
@ -396,7 +396,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
continue continue
} }
if msg.Tier >= uint(*tiersFlag) { if msg.Tier >= uint(*tiersFlag) {
if err = sendError(wsconn, errors.New("Invalid funding tier requested")); err != nil { if err = sendError(wsconn, errors.New("invalid funding tier requested")); err != nil {
log.Warn("Failed to send tier error to client", "err", err) log.Warn("Failed to send tier error to client", "err", err)
return return
} }
@ -433,7 +433,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
} }
if !result.Success { if !result.Success {
log.Warn("Captcha verification failed", "err", string(result.Errors)) log.Warn("Captcha verification failed", "err", string(result.Errors))
if err = sendError(wsconn, errors.New("Beep-bop, you're a robot!")); err != nil { if err = sendError(wsconn, errors.New("beep-bop, you're a robot")); err != nil {
log.Warn("Failed to send captcha failure to client", "err", err) log.Warn("Failed to send captcha failure to client", "err", err)
return return
} }
@ -462,7 +462,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
case *noauthFlag: case *noauthFlag:
username, avatar, address, err = authNoAuth(msg.URL) username, avatar, address, err = authNoAuth(msg.URL)
default: default:
err = errors.New("Something funky happened, please open an issue at https://github.com/XinFinOrg/XDPoSChain/issues") err = errors.New("something funky happened, please open an issue at https://github.com/XinFinOrg/XDPoSChain/issues")
} }
if err != nil { if err != nil {
if err = sendError(wsconn, err); err != nil { if err = sendError(wsconn, err); err != nil {
@ -517,7 +517,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
// Send an error if too frequent funding, othewise a success // Send an error if too frequent funding, othewise a success
if !fund { if !fund {
if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(timeout.Sub(time.Now())))); err != nil { // nolint: gosimple if err = sendError(wsconn, fmt.Errorf("%s left until next allowance", common.PrettyDuration(time.Until(timeout)))); err != nil {
log.Warn("Failed to send funding error to client", "err", err) log.Warn("Failed to send funding error to client", "err", err)
return return
} }
@ -657,7 +657,7 @@ func sendSuccess(conn *wsConn, msg string) error {
func authGitHub(url string) (string, string, common.Address, error) { func authGitHub(url string) (string, string, common.Address, error) {
// Retrieve the gist from the GitHub Gist APIs // Retrieve the gist from the GitHub Gist APIs
parts := strings.Split(url, "/") parts := strings.Split(url, "/")
req, _ := http.NewRequest("GET", "https://api.github.com/gists/"+parts[len(parts)-1], nil) req, _ := http.NewRequest(http.MethodGet, "https://api.github.com/gists/"+parts[len(parts)-1], nil)
if *githubUser != "" { if *githubUser != "" {
req.SetBasicAuth(*githubUser, *githubToken) req.SetBasicAuth(*githubUser, *githubToken)
} }
@ -679,7 +679,7 @@ func authGitHub(url string) (string, string, common.Address, error) {
return "", "", common.Address{}, err return "", "", common.Address{}, err
} }
if gist.Owner.Login == "" { if gist.Owner.Login == "" {
return "", "", common.Address{}, errors.New("Anonymous Gists not allowed") return "", "", common.Address{}, errors.New("anonymous gists not allowed")
} }
// Iterate over all the files and look for Ethereum addresses // Iterate over all the files and look for Ethereum addresses
var address common.Address var address common.Address
@ -690,7 +690,7 @@ func authGitHub(url string) (string, string, common.Address, error) {
} }
} }
if address == (common.Address{}) { if address == (common.Address{}) {
return "", "", common.Address{}, errors.New("No Ethereum address found to fund") return "", "", common.Address{}, errors.New("no Ethereum address found to fund")
} }
// Validate the user's existence since the API is unhelpful here // Validate the user's existence since the API is unhelpful here
if res, err = http.Head("https://github.com/" + gist.Owner.Login); err != nil { if res, err = http.Head("https://github.com/" + gist.Owner.Login); err != nil {
@ -699,7 +699,7 @@ func authGitHub(url string) (string, string, common.Address, error) {
res.Body.Close() res.Body.Close()
if res.StatusCode != 200 { if res.StatusCode != 200 {
return "", "", common.Address{}, errors.New("Invalid user... boom!") return "", "", common.Address{}, errors.New("invalid user... boom")
} }
// Everything passed validation, return the gathered infos // Everything passed validation, return the gathered infos
return gist.Owner.Login + "@github", fmt.Sprintf("https://github.com/%s.png?size=64", gist.Owner.Login), address, nil return gist.Owner.Login + "@github", fmt.Sprintf("https://github.com/%s.png?size=64", gist.Owner.Login), address, nil
@ -711,7 +711,7 @@ func authTwitter(url string) (string, string, common.Address, error) {
// Ensure the user specified a meaningful URL, no fancy nonsense // Ensure the user specified a meaningful URL, no fancy nonsense
parts := strings.Split(url, "/") parts := strings.Split(url, "/")
if len(parts) < 4 || parts[len(parts)-2] != "status" { if len(parts) < 4 || parts[len(parts)-2] != "status" {
return "", "", common.Address{}, errors.New("Invalid Twitter status URL") return "", "", common.Address{}, errors.New("invalid Twitter status URL")
} }
// Twitter's API isn't really friendly with direct links. Still, we don't // Twitter's API isn't really friendly with direct links. Still, we don't
// want to do ask read permissions from users, so just load the public posts and // want to do ask read permissions from users, so just load the public posts and
@ -725,7 +725,7 @@ func authTwitter(url string) (string, string, common.Address, error) {
// Resolve the username from the final redirect, no intermediate junk // Resolve the username from the final redirect, no intermediate junk
parts = strings.Split(res.Request.URL.String(), "/") parts = strings.Split(res.Request.URL.String(), "/")
if len(parts) < 4 || parts[len(parts)-2] != "status" { if len(parts) < 4 || parts[len(parts)-2] != "status" {
return "", "", common.Address{}, errors.New("Invalid Twitter status URL") return "", "", common.Address{}, errors.New("invalid Twitter status URL")
} }
username := parts[len(parts)-3] username := parts[len(parts)-3]
@ -735,7 +735,7 @@ func authTwitter(url string) (string, string, common.Address, error) {
} }
address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body)))
if address == (common.Address{}) { if address == (common.Address{}) {
return "", "", common.Address{}, errors.New("No Ethereum address found to fund") return "", "", common.Address{}, errors.New("no Ethereum address found to fund")
} }
var avatar string var avatar string
if parts = regexp.MustCompile("src=\"([^\"]+twimg.com/profile_images[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 { if parts = regexp.MustCompile("src=\"([^\"]+twimg.com/profile_images[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 {
@ -750,7 +750,7 @@ func authGooglePlus(url string) (string, string, common.Address, error) {
// Ensure the user specified a meaningful URL, no fancy nonsense // Ensure the user specified a meaningful URL, no fancy nonsense
parts := strings.Split(url, "/") parts := strings.Split(url, "/")
if len(parts) < 4 || parts[len(parts)-2] != "posts" { if len(parts) < 4 || parts[len(parts)-2] != "posts" {
return "", "", common.Address{}, errors.New("Invalid Google+ post URL") return "", "", common.Address{}, errors.New("invalid Google+ post URL")
} }
username := parts[len(parts)-3] username := parts[len(parts)-3]
@ -769,7 +769,7 @@ func authGooglePlus(url string) (string, string, common.Address, error) {
} }
address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body)))
if address == (common.Address{}) { if address == (common.Address{}) {
return "", "", common.Address{}, errors.New("No Ethereum address found to fund") return "", "", common.Address{}, errors.New("no Ethereum address found to fund")
} }
var avatar string var avatar string
if parts = regexp.MustCompile("src=\"([^\"]+googleusercontent.com[^\"]+photo.jpg)\"").FindStringSubmatch(string(body)); len(parts) == 2 { if parts = regexp.MustCompile("src=\"([^\"]+googleusercontent.com[^\"]+photo.jpg)\"").FindStringSubmatch(string(body)); len(parts) == 2 {
@ -784,7 +784,7 @@ func authFacebook(url string) (string, string, common.Address, error) {
// Ensure the user specified a meaningful URL, no fancy nonsense // Ensure the user specified a meaningful URL, no fancy nonsense
parts := strings.Split(url, "/") parts := strings.Split(url, "/")
if len(parts) < 4 || parts[len(parts)-2] != "posts" { if len(parts) < 4 || parts[len(parts)-2] != "posts" {
return "", "", common.Address{}, errors.New("Invalid Facebook post URL") return "", "", common.Address{}, errors.New("invalid Facebook post URL")
} }
username := parts[len(parts)-3] username := parts[len(parts)-3]
@ -803,7 +803,7 @@ func authFacebook(url string) (string, string, common.Address, error) {
} }
address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body))) address := common.HexToAddress(string(regexp.MustCompile("0x[0-9a-fA-F]{40}").Find(body)))
if address == (common.Address{}) { if address == (common.Address{}) {
return "", "", common.Address{}, errors.New("No Ethereum address found to fund") return "", "", common.Address{}, errors.New("no Ethereum address found to fund")
} }
var avatar string var avatar string
if parts = regexp.MustCompile("src=\"([^\"]+fbcdn.net[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 { if parts = regexp.MustCompile("src=\"([^\"]+fbcdn.net[^\"]+)\"").FindStringSubmatch(string(body)); len(parts) == 2 {
@ -818,7 +818,7 @@ func authFacebook(url string) (string, string, common.Address, error) {
func authNoAuth(url string) (string, string, common.Address, error) { func authNoAuth(url string) (string, string, common.Address, error) {
address := common.HexToAddress(regexp.MustCompile("0x[0-9a-fA-F]{40}").FindString(url)) address := common.HexToAddress(regexp.MustCompile("0x[0-9a-fA-F]{40}").FindString(url))
if address == (common.Address{}) { if address == (common.Address{}) {
return "", "", common.Address{}, errors.New("No Ethereum address found to fund") return "", "", common.Address{}, errors.New("no Ethereum address found to fund")
} }
return address.Hex() + "@noauth", "", address, nil return address.Hex() + "@noauth", "", address, nil
} }

View file

@ -92,15 +92,15 @@ func faucetHtml() (*asset, error) {
// It returns an error if the asset could not be found or // It returns an error if the asset could not be found or
// could not be loaded. // could not be loaded.
func Asset(name string) ([]byte, error) { func Asset(name string) ([]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok { if f, ok := _bindata[canonicalName]; ok {
a, err := f() a, err := f()
if err != nil { if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) return nil, fmt.Errorf("can't read Asset %s by error: %v", name, err)
} }
return a.bytes, nil return a.bytes, nil
} }
return nil, fmt.Errorf("Asset %s not found", name) return nil, fmt.Errorf("not found Asset %s", name)
} }
// AssetString returns the asset contents as a string (instead of a []byte). // AssetString returns the asset contents as a string (instead of a []byte).
@ -130,29 +130,29 @@ func MustAssetString(name string) string {
// It returns an error if the asset could not be found or // It returns an error if the asset could not be found or
// could not be loaded. // could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) { func AssetInfo(name string) (os.FileInfo, error) {
canonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok { if f, ok := _bindata[canonicalName]; ok {
a, err := f() a, err := f()
if err != nil { if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) return nil, fmt.Errorf("can't read AssetInfo %s by error: %v", name, err)
} }
return a.info, nil return a.info, nil
} }
return nil, fmt.Errorf("AssetInfo %s not found", name) return nil, fmt.Errorf("not found AssetInfo %s", name)
} }
// AssetDigest returns the digest of the file with the given name. It returns an // AssetDigest returns the digest of the file with the given name. It returns an
// error if the asset could not be found or the digest could not be loaded. // error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) { func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok { if f, ok := _bindata[canonicalName]; ok {
a, err := f() a, err := f()
if err != nil { if err != nil {
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err) return [sha256.Size]byte{}, fmt.Errorf("can't read AssetDigest %s by error: %v", name, err)
} }
return a.digest, nil return a.digest, nil
} }
return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name) return [sha256.Size]byte{}, fmt.Errorf("not found AssetDigest %s", name)
} }
// Digests returns a map of all known files and their checksums. // Digests returns a map of all known files and their checksums.
@ -203,17 +203,17 @@ const AssetDebug = false
func AssetDir(name string) ([]string, error) { func AssetDir(name string) ([]string, error) {
node := _bintree node := _bintree
if len(name) != 0 { if len(name) != 0 {
canonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.ReplaceAll(name, "\\", "/")
pathList := strings.Split(canonicalName, "/") pathList := strings.Split(canonicalName, "/")
for _, p := range pathList { for _, p := range pathList {
node = node.Children[p] node = node.Children[p]
if node == nil { if node == nil {
return nil, fmt.Errorf("Asset %s not found", name) return nil, fmt.Errorf("not found Asset %s", name)
} }
} }
} }
if node.Func != nil { if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name) return nil, fmt.Errorf("not found Asset %s", name)
} }
rv := make([]string, 0, len(node.Children)) rv := make([]string, 0, len(node.Children))
for childName := range node.Children { for childName := range node.Children {
@ -270,6 +270,6 @@ func RestoreAssets(dir, name string) error {
} }
func _filePath(dir, name string) string { func _filePath(dir, name string) string {
canonicalName := strings.Replace(name, "\\", "/", -1) canonicalName := strings.ReplaceAll(name, "\\", "/")
return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...) return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
} }

View file

@ -12,6 +12,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils" "github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
@ -20,7 +21,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/ethdb/leveldb" "github.com/XinFinOrg/XDPoSChain/ethdb/leveldb"
"github.com/XinFinOrg/XDPoSChain/rlp" "github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie" "github.com/XinFinOrg/XDPoSChain/trie"
"github.com/XinFinOrg/XDPoSChain/common/lru"
) )
var ( var (
@ -170,7 +170,7 @@ func getAllChilds(n StateNode, db *leveldb.Database) ([17]*StateNode, error) {
} }
if err == nil { if err == nil {
childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))} childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))}
} else if err != nil { } else {
_, ok := err.(*trie.MissingNodeError) _, ok := err.(*trie.MissingNodeError)
if !ok { if !ok {
return childs, err return childs, err
@ -187,7 +187,7 @@ func getAllChilds(n StateNode, db *leveldb.Database) ([17]*StateNode, error) {
} }
if err == nil { if err == nil {
childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)} childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)}
} else if err != nil { } else {
_, ok := err.(*trie.MissingNodeError) _, ok := err.(*trie.MissingNodeError)
if !ok { if !ok {
return childs, err return childs, err

View file

@ -19,21 +19,20 @@
// Here is an example of creating a 2 node network with the first node // Here is an example of creating a 2 node network with the first node
// connected to the second: // connected to the second:
// //
// $ p2psim node create // $ p2psim node create
// Created node01 // Created node01
// //
// $ p2psim node start node01 // $ p2psim node start node01
// Started node01 // Started node01
// //
// $ p2psim node create // $ p2psim node create
// Created node02 // Created node02
// //
// $ p2psim node start node02 // $ p2psim node start node02
// Started node02 // Started node02
//
// $ p2psim node connect node01 node02
// Connected node01 to node02
// //
// $ p2psim node connect node01 node02
// Connected node01 to node02
package main package main
import ( import (
@ -46,32 +45,77 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/p2p" "github.com/XinFinOrg/XDPoSChain/p2p"
"github.com/XinFinOrg/XDPoSChain/p2p/discover" "github.com/XinFinOrg/XDPoSChain/p2p/discover"
"github.com/XinFinOrg/XDPoSChain/p2p/simulations" "github.com/XinFinOrg/XDPoSChain/p2p/simulations"
"github.com/XinFinOrg/XDPoSChain/p2p/simulations/adapters" "github.com/XinFinOrg/XDPoSChain/p2p/simulations/adapters"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var client *simulations.Client var client *simulations.Client
var (
// global command flags
apiFlag = &cli.StringFlag{
Name: "api",
Value: "http://localhost:8888",
Usage: "simulation API URL",
EnvVars: []string{"P2PSIM_API_URL"},
}
// events subcommand flags
currentFlag = &cli.BoolFlag{
Name: "current",
Usage: "get existing nodes and conns first",
}
filterFlag = &cli.StringFlag{
Name: "filter",
Value: "",
Usage: "message filter",
}
// node create subcommand flags
nameFlag = &cli.StringFlag{
Name: "name",
Value: "",
Usage: "node name",
}
servicesFlag = &cli.StringFlag{
Name: "services",
Value: "",
Usage: "node services (comma separated)",
}
keyFlag = &cli.StringFlag{
Name: "key",
Value: "",
Usage: "node private key (hex encoded)",
}
// node rpc subcommand flags
subscribeFlag = &cli.BoolFlag{
Name: "subscribe",
Usage: "method is a subscription",
}
)
var (
// Git information set by linker when building with ci.go.
gitCommit string
)
func main() { func main() {
app := cli.NewApp() app := flags.NewApp(gitCommit, "devp2p simulation command-line client")
app.Usage = "devp2p simulation command-line client" app.Usage = "devp2p simulation command-line client"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag{ apiFlag,
Name: "api",
Value: "http://localhost:8888",
Usage: "simulation API URL",
EnvVar: "P2PSIM_API_URL",
},
} }
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
client = simulations.NewClient(ctx.GlobalString("api")) client = simulations.NewClient(ctx.String("api"))
return nil return nil
} }
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "show", Name: "show",
Usage: "show network information", Usage: "show network information",
@ -82,15 +126,8 @@ func main() {
Usage: "stream network events", Usage: "stream network events",
Action: streamNetwork, Action: streamNetwork,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ currentFlag,
Name: "current", filterFlag,
Usage: "get existing nodes and conns first",
},
cli.StringFlag{
Name: "filter",
Value: "",
Usage: "message filter",
},
}, },
}, },
{ {
@ -107,7 +144,7 @@ func main() {
Name: "node", Name: "node",
Usage: "manage simulation nodes", Usage: "manage simulation nodes",
Action: listNodes, Action: listNodes,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "list", Name: "list",
Usage: "list nodes", Usage: "list nodes",
@ -118,21 +155,9 @@ func main() {
Usage: "create a node", Usage: "create a node",
Action: createNode, Action: createNode,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ nameFlag,
Name: "name", servicesFlag,
Value: "", keyFlag,
Usage: "node name",
},
cli.StringFlag{
Name: "services",
Value: "",
Usage: "node services (comma separated)",
},
cli.StringFlag{
Name: "key",
Value: "",
Usage: "node private key (hex encoded)",
},
}, },
}, },
{ {
@ -171,10 +196,7 @@ func main() {
Usage: "call a node RPC method", Usage: "call a node RPC method",
Action: rpcNode, Action: rpcNode,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.BoolFlag{ subscribeFlag,
Name: "subscribe",
Usage: "method is a subscription",
},
}, },
}, },
}, },
@ -184,7 +206,7 @@ func main() {
} }
func showNetwork(ctx *cli.Context) error { func showNetwork(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
network, err := client.GetNetwork() network, err := client.GetNetwork()
@ -199,7 +221,7 @@ func showNetwork(ctx *cli.Context) error {
} }
func streamNetwork(ctx *cli.Context) error { func streamNetwork(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
events := make(chan *simulations.Event) events := make(chan *simulations.Event)
@ -225,7 +247,7 @@ func streamNetwork(ctx *cli.Context) error {
} }
func createSnapshot(ctx *cli.Context) error { func createSnapshot(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
snap, err := client.CreateSnapshot() snap, err := client.CreateSnapshot()
@ -236,7 +258,7 @@ func createSnapshot(ctx *cli.Context) error {
} }
func loadSnapshot(ctx *cli.Context) error { func loadSnapshot(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
snap := &simulations.Snapshot{} snap := &simulations.Snapshot{}
@ -247,7 +269,7 @@ func loadSnapshot(ctx *cli.Context) error {
} }
func listNodes(ctx *cli.Context) error { func listNodes(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodes, err := client.GetNodes() nodes, err := client.GetNodes()
@ -272,7 +294,7 @@ func protocolList(node *p2p.NodeInfo) []string {
} }
func createNode(ctx *cli.Context) error { func createNode(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
config := &adapters.NodeConfig{ config := &adapters.NodeConfig{
@ -298,11 +320,10 @@ func createNode(ctx *cli.Context) error {
} }
func showNode(ctx *cli.Context) error { func showNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
node, err := client.GetNode(nodeName) node, err := client.GetNode(nodeName)
if err != nil { if err != nil {
return err return err
@ -323,11 +344,10 @@ func showNode(ctx *cli.Context) error {
} }
func startNode(ctx *cli.Context) error { func startNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
if err := client.StartNode(nodeName); err != nil { if err := client.StartNode(nodeName); err != nil {
return err return err
} }
@ -336,11 +356,10 @@ func startNode(ctx *cli.Context) error {
} }
func stopNode(ctx *cli.Context) error { func stopNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
if err := client.StopNode(nodeName); err != nil { if err := client.StopNode(nodeName); err != nil {
return err return err
} }
@ -349,12 +368,12 @@ func stopNode(ctx *cli.Context) error {
} }
func connectNode(ctx *cli.Context) error { func connectNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 2 {
if len(args) != 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] args := ctx.Args()
peerName := args[1] nodeName := args.Get(0)
peerName := args.Get(1)
if err := client.ConnectNode(nodeName, peerName); err != nil { if err := client.ConnectNode(nodeName, peerName); err != nil {
return err return err
} }
@ -364,11 +383,11 @@ func connectNode(ctx *cli.Context) error {
func disconnectNode(ctx *cli.Context) error { func disconnectNode(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) != 2 { if args.Len() != 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := args.Get(0)
peerName := args[1] peerName := args.Get(1)
if err := client.DisconnectNode(nodeName, peerName); err != nil { if err := client.DisconnectNode(nodeName, peerName); err != nil {
return err return err
} }
@ -378,21 +397,21 @@ func disconnectNode(ctx *cli.Context) error {
func rpcNode(ctx *cli.Context) error { func rpcNode(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) < 2 { if args.Len() < 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := args.Get(0)
method := args[1] method := args.Get(1)
rpcClient, err := client.RPCClient(context.Background(), nodeName) rpcClient, err := client.RPCClient(context.Background(), nodeName)
if err != nil { if err != nil {
return err return err
} }
if ctx.Bool("subscribe") { if ctx.Bool("subscribe") {
return rpcSubscribe(rpcClient, ctx.App.Writer, method, args[3:]...) return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...)
} }
var result interface{} var result interface{}
params := make([]interface{}, len(args[3:])) params := make([]interface{}, len(args.Slice()[3:]))
for i, v := range args[3:] { for i, v := range args.Slice()[3:] {
params[i] = v params[i] = v
} }
if err := rpcClient.Call(&result, method, params...); err != nil { if err := rpcClient.Call(&result, method, params...); err != nil {

View file

@ -197,7 +197,7 @@ func checkExplorer(client *sshClient, network string) (*explorerInfos, error) {
// Run a sanity check to see if the devp2p is reachable // Run a sanity check to see if the devp2p is reachable
nodePort := infos.portmap[infos.envvars["NODE_PORT"]] nodePort := infos.portmap[infos.envvars["NODE_PORT"]]
if err = checkPort(client.server, nodePort); err != nil { if err = checkPort(client.server, nodePort); err != nil {
log.Warn(fmt.Sprintf("Explorer devp2p port seems unreachable"), "server", client.server, "port", nodePort, "err", err) log.Warn("Explorer devp2p port seems unreachable", "server", client.server, "port", nodePort, "err", err)
} }
// Assemble and return the useful infos // Assemble and return the useful infos
stats := &explorerInfos{ stats := &explorerInfos{

Some files were not shown because too many files have changed in this diff Show more