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
les/ @zsfelfoldi
light/ @zsfelfoldi
mobile/ @karalabe
p2p/ @fjl @zsfelfoldi
whisper/ @gballet @gluk256

View file

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

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

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

View file

@ -4,7 +4,7 @@
GOBIN = $(shell pwd)/build/bin
GOFMT = gofmt
GO ?= 1.21.3
GO ?= 1.22.10
GO_PACKAGES = .
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/XDCxDAO"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/state"
@ -17,7 +18,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/p2p"
"github.com/XinFinOrg/XDPoSChain/rpc"
lru "github.com/hashicorp/golang-lru"
"golang.org/x/sync/syncmap"
)
@ -59,8 +59,8 @@ type XDCX struct {
sdkNode bool
settings syncmap.Map // holds configuration settings that can be dynamically changed
tokenDecimalCache *lru.Cache
orderCache *lru.Cache
tokenDecimalCache *lru.Cache[common.Address, *big.Int]
orderCache *lru.Cache[common.Hash, map[common.Hash]tradingstate.OrderHistoryItem]
}
func (XDCx *XDCX) Protocols() []p2p.Protocol {
@ -94,19 +94,11 @@ func NewMongoDBEngine(cfg *Config) *XDCxDAO.MongoDatabase {
}
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{
orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil),
tokenDecimalCache: tokenDecimalCache,
orderCache: orderCache,
tokenDecimalCache: lru.NewCache[common.Address, *big.Int](defaultCacheLimit),
orderCache: lru.NewCache[common.Hash, map[common.Hash]tradingstate.OrderHistoryItem](tradingstate.OrderCacheLimit),
}
// default DBEngine: levelDB
@ -275,11 +267,11 @@ func (XDCx *XDCX) GetAveragePriceLastEpoch(chain consensus.ChainContext, statedb
if inversePrice != nil && inversePrice.Sign() > 0 {
quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, quoteToken)
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)
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).Div(price, inversePrice)
@ -302,7 +294,7 @@ func (XDCx *XDCX) ConvertXDCToToken(chain consensus.ChainContext, statedb *state
tokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, token)
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).Div(tokenQuantity, tokenPriceInXDC)
@ -568,7 +560,7 @@ func (XDCx *XDCX) GetTradingState(block *types.Block, author common.Address) (*t
return nil, err
}
if XDCx.StateCache == nil {
return nil, errors.New("Not initialized XDCx")
return nil, errors.New("not initialized XDCx")
}
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) {
var orderCacheAtTxHash map[common.Hash]tradingstate.OrderHistoryItem
c, ok := XDCx.orderCache.Get(txhash)
if !ok || c == nil {
orderCacheAtTxHash, ok := XDCx.orderCache.Get(txhash)
if !ok || orderCacheAtTxHash == nil {
orderCacheAtTxHash = make(map[common.Hash]tradingstate.OrderHistoryItem)
} else {
orderCacheAtTxHash = c.(map[common.Hash]tradingstate.OrderHistoryItem)
}
orderKey := tradingstate.GetOrderHistoryKey(baseToken, quoteToken, orderHash)
_, ok = orderCacheAtTxHash[orderKey]
@ -629,16 +618,15 @@ func (XDCx *XDCX) RollbackReorgTxMatch(txhash common.Hash) error {
items := db.GetListItemByTxHash(txhash, &tradingstate.OrderItem{})
if items != nil {
for _, order := range items.([]*tradingstate.OrderItem) {
c, ok := XDCx.orderCache.Get(txhash)
log.Debug("XDCx reorg: rollback order", "txhash", txhash.Hex(), "order", tradingstate.ToJSON(order), "orderHistoryItem", c)
if !ok {
orderCacheAtTxHash, ok := XDCx.orderCache.Get(txhash)
log.Debug("XDCx reorg: rollback order", "txhash", txhash.Hex(), "order", tradingstate.ToJSON(order), "orderHistoryItem", orderCacheAtTxHash)
if !ok || orderCacheAtTxHash == nil {
log.Debug("XDCx reorg: remove order due to no orderCache", "order", tradingstate.ToJSON(order))
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))
}
continue
}
orderCacheAtTxHash := c.(map[common.Hash]tradingstate.OrderHistoryItem)
orderHistoryItem := orderCacheAtTxHash[tradingstate.GetOrderHistoryKey(order.BaseToken, order.QuoteToken, order.Hash)]
if (orderHistoryItem == tradingstate.OrderHistoryItem{}) {
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))
quoteTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, oldestOrder.QuoteToken)
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)
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) {
baseTokenDecimal, err := XDCx.GetTokenDecimal(chain, statedb, makerOrder.BaseToken)
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)
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 {
quotePrice = quoteTokenDecimal
@ -526,7 +526,7 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *tradingsta
matchingFee = new(big.Int).Add(matchingFee, common.RelayerFee)
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{}
//Checking balance
@ -656,9 +656,10 @@ func (XDCx *XDCX) ProcessCancelOrder(header *types.Header, tradingStateDB *tradi
}
log.Debug("ProcessCancelOrder", "baseToken", originOrder.BaseToken, "quoteToken", originOrder.QuoteToken)
feeRate := tradingstate.GetExRelayerFee(originOrder.ExchangeAddress, statedb)
tokenCancelFee, tokenPriceInXDC := common.Big0, common.Big0
var tokenCancelFee, tokenPriceInXDC *big.Int
if !chain.Config().IsTIPXDCXCancellationFee(header.Number) {
tokenCancelFee = getCancelFeeV1(baseTokenDecimal, feeRate, &originOrder)
tokenPriceInXDC = common.Big0
} else {
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
// deprecated after hardfork at TIPXDCXCancellationFee
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 {
// SELL 1 BTC => XDC ,,
// 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 {
return common.Big0, common.Big0
}
cancelFee := big.NewInt(0)
tokenPriceInXDC := big.NewInt(0)
var cancelFee, tokenPriceInXDC *big.Int
var err error
if order.Side == tradingstate.Ask {
cancelFee, tokenPriceInXDC, err = XDCx.ConvertXDCToToken(chain, statedb, tradingStateDb, order.BaseToken, common.RelayerCancelFee)

View file

@ -4,15 +4,14 @@ import (
"math/big"
"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/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/common"
"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/log"
)
// 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) {
if tokenDecimal, ok := XDCx.tokenDecimalCache.Get(tokenAddr); ok {
return tokenDecimal.(*big.Int), nil
if tokenDecimal, ok := XDCx.tokenDecimalCache.Get(tokenAddr); ok && tokenDecimal != nil {
return tokenDecimal, nil
}
if tokenAddr == common.XDCNativeAddressBinary {
XDCx.tokenDecimalCache.Add(tokenAddr, common.BasePrice)

View file

@ -23,7 +23,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
)
// 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
// reasonable chain reorg depths will hit an existing trie.
maxPastTries = 12
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
)
// 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
// high level trie abstraction.
func NewDatabase(db ethdb.Database) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{
db: trie.NewDatabase(db),
codeSizeCache: csc,
db: trie.NewDatabase(db),
}
}
type cachingDB struct {
db *trie.Database
mu sync.Mutex
pastTries []*XDCXTrie
codeSizeCache *lru.Cache
db *trie.Database
mu sync.Mutex
pastTries []*XDCXTrie
}
// OpenTrie opens the main account trie.

View file

@ -47,13 +47,13 @@ type DumpOrderBookInfo struct {
LowestLiquidationPrice *big.Int
}
func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getAsksTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
@ -65,15 +65,15 @@ func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]Dum
} else {
var data orderList
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)
mapResult[price] = stateOrderList.DumpOrderList(self.db)
stateOrderList := newStateOrderList(t, Ask, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.DumpOrderList(t.db)
}
}
for priceHash, stateOrderList := range exhangeObject.stateAskObjects {
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{}
@ -90,13 +90,13 @@ func (self *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]Dum
return result, nil
}
func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getBidsTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
@ -108,15 +108,15 @@ func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]Dum
} else {
var data orderList
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)
mapResult[price] = stateOrderList.DumpOrderList(self.db)
stateOrderList := newStateOrderList(t, Bid, orderBook, priceHash, data, nil)
mapResult[price] = stateOrderList.DumpOrderList(t.db)
}
}
for priceHash, stateOrderList := range exhangeObject.stateBidObjects {
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{}
@ -133,13 +133,13 @@ func (self *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]Dum
return mapResult, nil
}
func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getBidsTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
@ -151,9 +151,9 @@ func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.In
} else {
var data orderList
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
}
}
@ -176,13 +176,13 @@ func (self *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.In
return mapResult, nil
}
func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getAsksTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
@ -194,9 +194,9 @@ func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.In
} else {
var data orderList
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
}
}
@ -218,22 +218,23 @@ func (self *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.In
}
return result, nil
}
func (self *stateOrderList) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil))
func (s *stateOrderList) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
continue
}
if _, exist := self.cachedStorage[keyHash]; exist {
if _, exist := s.cachedStorage[keyHash]; exist {
continue
} else {
_, content, _, _ := rlp.Split(orderListIt.Value)
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) {
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 {
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 {
result.Orders[id] = mapResult.Orders[id]
}
return mapResult
}
func (self *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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.LastPrice = exhangeObject.data.LastPrice
@ -264,29 +265,29 @@ func (self *TradingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrder
result.MediumPriceBeforeEpoch = exhangeObject.data.MediumPriceBeforeEpoch
result.Nonce = exhangeObject.data.Nonce
result.TotalQuantity = exhangeObject.data.TotalQuantity
result.BestAsk = new(big.Int).SetBytes(exhangeObject.getBestPriceAsksTrie(self.db).Bytes())
result.BestBid = new(big.Int).SetBytes(exhangeObject.getBestBidsTrie(self.db).Bytes())
lowestPrice, _ := exhangeObject.getLowestLiquidationPrice(self.db)
result.BestAsk = new(big.Int).SetBytes(exhangeObject.getBestPriceAsksTrie(t.db).Bytes())
result.BestBid = new(big.Int).SetBytes(exhangeObject.getBestBidsTrie(t.db).Bytes())
lowestPrice, _ := exhangeObject.getLowestLiquidationPrice(t.db)
result.LowestLiquidationPrice = new(big.Int).SetBytes(lowestPrice.Bytes())
return result, nil
}
func (self *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil))
func (s *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: s.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
continue
}
if _, exist := self.cachedStorage[keyHash]; exist {
if _, exist := s.cachedStorage[keyHash]; exist {
continue
} else {
_, content, _, _ := rlp.Split(orderListIt.Value)
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) {
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 {
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 {
result.Orders[id] = mapResult.Orders[id]
}
return mapResult
}
func (self *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, error) {
result := DumpLendingBook{Volume: self.Volume(), LendingBooks: map[common.Hash]DumpOrderList{}}
it := trie.NewIterator(self.getTrie(db).NodeIterator(nil))
func (l *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, error) {
result := DumpLendingBook{Volume: l.Volume(), LendingBooks: map[common.Hash]DumpOrderList{}}
it := trie.NewIterator(l.getTrie(db).NodeIterator(nil))
for it.Next() {
lendingBook := common.BytesToHash(it.Key)
if common.EmptyHash(lendingBook) {
continue
}
if _, exist := self.stateLendingBooks[lendingBook]; exist {
if _, exist := l.stateLendingBooks[lendingBook]; exist {
continue
} else {
var data orderList
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)
}
}
for lendingBook, stateLendingBook := range self.stateLendingBooks {
for lendingBook, stateLendingBook := range l.stateLendingBooks {
if !common.EmptyHash(lendingBook) {
result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db)
}
@ -332,13 +333,13 @@ func (self *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook
return result, nil
}
func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map[*big.Int]DumpLendingBook, error) {
exhangeObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map[*big.Int]DumpLendingBook, error) {
exhangeObject := t.getStateExchangeObject(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getLiquidationPriceTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getLiquidationPriceTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
@ -350,10 +351,10 @@ func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map
} else {
var data orderList
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)
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(self.db)
liquidationPriceState := newLiquidationPriceState(t, orderBook, priceHash, data, nil)
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(t.db)
if err != nil {
return nil, err
}
@ -362,7 +363,7 @@ func (self *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map
}
for priceHash, liquidationPriceState := range exhangeObject.liquidationPriceStates {
if liquidationPriceState.Volume().Sign() > 0 {
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(self.db)
dumpLendingBook, err := liquidationPriceState.DumpLendingBook(t.db)
if err != nil {
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"])
toTokenLength := statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), common.BigToHash(toTokenSlot)).Big().Uint64()
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{}
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)
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 {
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 {
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 {
return rlp.Encode(w, self.data)
func (s *stateLendingBook) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, s.data)
}
func (self *stateLendingBook) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
func (s *stateLendingBook) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
}
}
func (self *stateLendingBook) getTrie(db Database) Trie {
if self.trie == nil {
func (s *stateLendingBook) getTrie(db Database) Trie {
if s.trie == nil {
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 {
self.trie, _ = db.OpenStorageTrie(self.price, EmptyHash)
self.setError(fmt.Errorf("can't create storage trie: %v", err))
s.trie, _ = db.OpenStorageTrie(s.price, EmptyHash)
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 {
amount, exists := self.cachedStorage[lendingId]
func (s *stateLendingBook) Exist(db Database, lendingId common.Hash) bool {
amount, exists := s.cachedStorage[lendingId]
if exists {
return true
}
// 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 {
self.setError(err)
s.setError(err)
return false
}
if len(enc) > 0 {
_, content, _, err := rlp.Split(enc)
if err != nil {
self.setError(err)
s.setError(err)
}
amount.SetBytes(content)
}
if (amount != common.Hash{}) {
self.cachedStorage[lendingId] = amount
s.cachedStorage[lendingId] = amount
}
return true
}
func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
func (s *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
tradeIds := []common.Hash{}
lendingBookTrie := self.getTrie(db)
lendingBookTrie := s.getTrie(db)
if lendingBookTrie == nil {
return tradeIds
}
for id, value := range self.cachedStorage {
for id, value := range s.cachedStorage {
if !common.EmptyHash(value) {
tradeIds = append(tradeIds, id)
}
@ -125,7 +125,7 @@ func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil))
for orderListIt.Next() {
id := common.BytesToHash(orderListIt.Key)
if _, exist := self.cachedStorage[id]; exist {
if _, exist := s.cachedStorage[id]; exist {
continue
}
tradeIds = append(tradeIds, id)
@ -133,83 +133,83 @@ func (self *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
return tradeIds
}
func (self *stateLendingBook) insertTradingId(db Database, tradeId common.Hash) {
self.setTradingId(tradeId, tradeId)
self.setError(self.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
func (s *stateLendingBook) insertTradingId(db Database, tradeId common.Hash) {
s.setTradingId(tradeId, tradeId)
s.setError(s.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
}
func (self *stateLendingBook) removeTradingId(db Database, tradeId common.Hash) {
tr := self.getTrie(db)
self.setError(tr.TryDelete(tradeId[:]))
self.setTradingId(tradeId, EmptyHash)
func (s *stateLendingBook) removeTradingId(db Database, tradeId common.Hash) {
tr := s.getTrie(db)
s.setError(tr.TryDelete(tradeId[:]))
s.setTradingId(tradeId, EmptyHash)
}
func (self *stateLendingBook) setTradingId(tradeId common.Hash, value common.Hash) {
self.cachedStorage[tradeId] = value
self.dirtyStorage[tradeId] = value
func (s *stateLendingBook) setTradingId(tradeId common.Hash, value common.Hash) {
s.cachedStorage[tradeId] = value
s.dirtyStorage[tradeId] = value
if self.onDirty != nil {
self.onDirty(self.lendingBook)
self.onDirty = nil
if s.onDirty != nil {
s.onDirty(s.lendingBook)
s.onDirty = nil
}
}
func (self *stateLendingBook) updateTrie(db Database) Trie {
tr := self.getTrie(db)
for key, value := range self.dirtyStorage {
delete(self.dirtyStorage, key)
func (s *stateLendingBook) updateTrie(db Database) Trie {
tr := s.getTrie(db)
for key, value := range s.dirtyStorage {
delete(s.dirtyStorage, key)
if value == EmptyHash {
self.setError(tr.TryDelete(key[:]))
s.setError(tr.TryDelete(key[:]))
continue
}
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
self.setError(tr.TryUpdate(key[:], v))
s.setError(tr.TryUpdate(key[:], v))
}
return tr
}
func (self *stateLendingBook) updateRoot(db Database) error {
self.updateTrie(db)
if self.dbErr != nil {
return self.dbErr
func (s *stateLendingBook) updateRoot(db Database) error {
s.updateTrie(db)
if s.dbErr != nil {
return s.dbErr
}
root, err := self.trie.Commit(nil)
root, err := s.trie.Commit(nil)
if err == nil {
self.data.Root = root
s.data.Root = root
}
return err
}
func (self *stateLendingBook) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateLendingBook {
stateLendingBook := newStateLendingBook(self.lendingBook, self.orderBook, self.price, self.data, onDirty)
if self.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(self.trie)
func (s *stateLendingBook) deepCopy(db *TradingStateDB, onDirty func(price common.Hash)) *stateLendingBook {
stateLendingBook := newStateLendingBook(s.lendingBook, s.orderBook, s.price, s.data, onDirty)
if s.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(s.trie)
}
for key, value := range self.dirtyStorage {
for key, value := range s.dirtyStorage {
stateLendingBook.dirtyStorage[key] = value
}
for key, value := range self.cachedStorage {
for key, value := range s.cachedStorage {
stateLendingBook.cachedStorage[key] = value
}
return stateLendingBook
}
func (c *stateLendingBook) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount))
func (s *stateLendingBook) AddVolume(amount *big.Int) {
s.setVolume(new(big.Int).Add(s.data.Volume, amount))
}
func (c *stateLendingBook) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount))
func (s *stateLendingBook) subVolume(amount *big.Int) {
s.setVolume(new(big.Int).Sub(s.data.Volume, amount))
}
func (self *stateLendingBook) setVolume(volume *big.Int) {
self.data.Volume = volume
if self.onDirty != nil {
self.onDirty(self.lendingBook)
self.onDirty = nil
func (s *stateLendingBook) setVolume(volume *big.Int) {
s.data.Volume = volume
if s.onDirty != nil {
s.onDirty(s.lendingBook)
s.onDirty = nil
}
}
func (self *stateLendingBook) Volume() *big.Int {
return self.data.Volume
func (s *stateLendingBook) Volume() *big.Int {
return s.data.Volume
}

View file

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

View file

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

View file

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

View file

@ -66,35 +66,35 @@ type tradingExchanges struct {
}
// empty returns whether the orderId is considered empty.
func (s *tradingExchanges) empty() bool {
if s.data.Nonce != 0 {
func (te *tradingExchanges) empty() bool {
if te.data.Nonce != 0 {
return false
}
if s.data.LendingCount != nil && s.data.LendingCount.Sign() > 0 {
if te.data.LendingCount != nil && te.data.LendingCount.Sign() > 0 {
return false
}
if s.data.LastPrice != nil && s.data.LastPrice.Sign() > 0 {
if te.data.LastPrice != nil && te.data.LastPrice.Sign() > 0 {
return false
}
if s.data.MediumPrice != nil && s.data.MediumPrice.Sign() > 0 {
if te.data.MediumPrice != nil && te.data.MediumPrice.Sign() > 0 {
return false
}
if s.data.MediumPriceBeforeEpoch != nil && s.data.MediumPriceBeforeEpoch.Sign() > 0 {
if te.data.MediumPriceBeforeEpoch != nil && te.data.MediumPriceBeforeEpoch.Sign() > 0 {
return false
}
if s.data.TotalQuantity != nil && s.data.TotalQuantity.Sign() > 0 {
if te.data.TotalQuantity != nil && te.data.TotalQuantity.Sign() > 0 {
return false
}
if !common.EmptyHash(s.data.AskRoot) {
if !common.EmptyHash(te.data.AskRoot) {
return false
}
if !common.EmptyHash(s.data.BidRoot) {
if !common.EmptyHash(te.data.BidRoot) {
return false
}
if !common.EmptyHash(s.data.OrderRoot) {
if !common.EmptyHash(te.data.OrderRoot) {
return false
}
if !common.EmptyHash(s.data.LiquidationPriceRoot) {
if !common.EmptyHash(te.data.LiquidationPriceRoot) {
return false
}
return true
@ -119,46 +119,46 @@ func newStateExchanges(db *TradingStateDB, hash common.Hash, data tradingExchang
}
// EncodeRLP implements rlp.Encoder.
func (c *tradingExchanges) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, c.data)
func (te *tradingExchanges) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, te.data)
}
// setError remembers the first non-nil error it is called with.
func (self *tradingExchanges) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
func (te *tradingExchanges) setError(err error) {
if te.dbErr == nil {
te.dbErr = err
}
}
func (c *tradingExchanges) getAsksTrie(db Database) Trie {
if c.asksTrie == nil {
func (te *tradingExchanges) getAsksTrie(db Database) Trie {
if te.asksTrie == nil {
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 {
c.asksTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create asks trie: %v", err))
te.asksTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
te.setError(fmt.Errorf("can't create asks trie: %v", err))
}
}
return c.asksTrie
return te.asksTrie
}
func (c *tradingExchanges) getOrdersTrie(db Database) Trie {
if c.ordersTrie == nil {
func (te *tradingExchanges) getOrdersTrie(db Database) Trie {
if te.ordersTrie == nil {
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 {
c.ordersTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create asks trie: %v", err))
te.ordersTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
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 {
trie := c.getAsksTrie(db)
func (te *tradingExchanges) getBestPriceAsksTrie(db Database) common.Hash {
trie := te.getAsksTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
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
}
if len(encKey) == 0 || len(encValue) == 0 {
@ -166,23 +166,23 @@ func (c *tradingExchanges) getBestPriceAsksTrie(db Database) common.Hash {
return EmptyHash
}
price := common.BytesToHash(encKey)
if _, exit := c.stateAskObjects[price]; !exit {
if _, exit := te.stateAskObjects[price]; !exit {
var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash
}
obj := newStateOrderList(c.db, Bid, c.orderBookHash, price, data, c.MarkStateAskObjectDirty)
c.stateAskObjects[price] = obj
obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateAskObjectDirty)
te.stateAskObjects[price] = obj
}
return common.BytesToHash(encKey)
}
func (c *tradingExchanges) getBestBidsTrie(db Database) common.Hash {
trie := c.getBidsTrie(db)
func (te *tradingExchanges) getBestBidsTrie(db Database) common.Hash {
trie := te.getBidsTrie(db)
encKey, encValue, err := trie.TryGetBestRightKeyAndValue()
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
}
if len(encKey) == 0 || len(encValue) == 0 {
@ -190,27 +190,27 @@ func (c *tradingExchanges) getBestBidsTrie(db Database) common.Hash {
return EmptyHash
}
price := common.BytesToHash(encKey)
if _, exit := c.stateBidObjects[price]; !exit {
if _, exit := te.stateBidObjects[price]; !exit {
var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best bid trie", "err", err)
return EmptyHash
}
// Insert into the live set.
obj := newStateOrderList(c.db, Bid, c.orderBookHash, price, data, c.MarkStateBidObjectDirty)
c.stateBidObjects[price] = obj
obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateBidObjectDirty)
te.stateBidObjects[price] = obj
}
return common.BytesToHash(encKey)
}
// updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *tradingExchanges) updateAsksTrie(db Database) Trie {
tr := self.getAsksTrie(db)
for price, orderList := range self.stateAskObjects {
if _, isDirty := self.stateAskObjectsDirty[price]; isDirty {
delete(self.stateAskObjectsDirty, price)
func (te *tradingExchanges) updateAsksTrie(db Database) Trie {
tr := te.getAsksTrie(db)
for price, orderList := range te.stateAskObjects {
if _, isDirty := te.stateAskObjectsDirty[price]; isDirty {
delete(te.stateAskObjectsDirty, price)
if orderList.empty() {
self.setError(tr.TryDelete(price[:]))
te.setError(tr.TryDelete(price[:]))
continue
}
err := orderList.updateRoot(db)
@ -219,7 +219,7 @@ func (self *tradingExchanges) updateAsksTrie(db Database) Trie {
}
// Encoding []byte cannot fail, ok to ignore the error.
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.
// This updates the trie root.
func (self *tradingExchanges) updateAsksRoot(db Database) error {
self.updateAsksTrie(db)
if self.dbErr != nil {
return self.dbErr
func (te *tradingExchanges) updateAsksRoot(db Database) error {
te.updateAsksTrie(db)
if te.dbErr != nil {
return te.dbErr
}
self.data.AskRoot = self.asksTrie.Hash()
te.data.AskRoot = te.asksTrie.Hash()
return nil
}
// CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root.
func (self *tradingExchanges) CommitAsksTrie(db Database) error {
self.updateAsksTrie(db)
if self.dbErr != nil {
return self.dbErr
func (te *tradingExchanges) CommitAsksTrie(db Database) error {
te.updateAsksTrie(db)
if te.dbErr != nil {
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
if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil
@ -255,31 +255,31 @@ func (self *tradingExchanges) CommitAsksTrie(db Database) error {
return nil
})
if err == nil {
self.data.AskRoot = root
te.data.AskRoot = root
}
return err
}
func (c *tradingExchanges) getBidsTrie(db Database) Trie {
if c.bidsTrie == nil {
func (te *tradingExchanges) getBidsTrie(db Database) Trie {
if te.bidsTrie == nil {
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 {
c.bidsTrie, _ = db.OpenStorageTrie(c.orderBookHash, EmptyHash)
c.setError(fmt.Errorf("can't create bids trie: %v", err))
te.bidsTrie, _ = db.OpenStorageTrie(te.orderBookHash, EmptyHash)
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.
func (self *tradingExchanges) updateBidsTrie(db Database) Trie {
tr := self.getBidsTrie(db)
for price, orderList := range self.stateBidObjects {
if _, isDirty := self.stateBidObjectsDirty[price]; isDirty {
delete(self.stateBidObjectsDirty, price)
func (te *tradingExchanges) updateBidsTrie(db Database) Trie {
tr := te.getBidsTrie(db)
for price, orderList := range te.stateBidObjects {
if _, isDirty := te.stateBidObjectsDirty[price]; isDirty {
delete(te.stateBidObjectsDirty, price)
if orderList.empty() {
self.setError(tr.TryDelete(price[:]))
te.setError(tr.TryDelete(price[:]))
continue
}
err := orderList.updateRoot(db)
@ -288,25 +288,25 @@ func (self *tradingExchanges) updateBidsTrie(db Database) Trie {
}
// Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderList)
self.setError(tr.TryUpdate(price[:], v))
te.setError(tr.TryUpdate(price[:], v))
}
}
return tr
}
func (self *tradingExchanges) updateBidsRoot(db Database) {
self.updateBidsTrie(db)
self.data.BidRoot = self.bidsTrie.Hash()
func (te *tradingExchanges) updateBidsRoot(db Database) {
te.updateBidsTrie(db)
te.data.BidRoot = te.bidsTrie.Hash()
}
// CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root.
func (self *tradingExchanges) CommitBidsTrie(db Database) error {
self.updateBidsTrie(db)
if self.dbErr != nil {
return self.dbErr
func (te *tradingExchanges) CommitBidsTrie(db Database) error {
te.updateBidsTrie(db)
if te.dbErr != nil {
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
if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil
@ -317,116 +317,116 @@ func (self *tradingExchanges) CommitBidsTrie(db Database) error {
return nil
})
if err == nil {
self.data.BidRoot = root
te.data.BidRoot = root
}
return err
}
func (self *tradingExchanges) deepCopy(db *TradingStateDB, onDirty func(hash common.Hash)) *tradingExchanges {
stateExchanges := newStateExchanges(db, self.orderBookHash, self.data, onDirty)
if self.asksTrie != nil {
stateExchanges.asksTrie = db.db.CopyTrie(self.asksTrie)
func (te *tradingExchanges) deepCopy(db *TradingStateDB, onDirty func(hash common.Hash)) *tradingExchanges {
stateExchanges := newStateExchanges(db, te.orderBookHash, te.data, onDirty)
if te.asksTrie != nil {
stateExchanges.asksTrie = db.db.CopyTrie(te.asksTrie)
}
if self.bidsTrie != nil {
stateExchanges.bidsTrie = db.db.CopyTrie(self.bidsTrie)
if te.bidsTrie != nil {
stateExchanges.bidsTrie = db.db.CopyTrie(te.bidsTrie)
}
if self.ordersTrie != nil {
stateExchanges.ordersTrie = db.db.CopyTrie(self.ordersTrie)
if te.ordersTrie != nil {
stateExchanges.ordersTrie = db.db.CopyTrie(te.ordersTrie)
}
for price, bidObject := range self.stateBidObjects {
stateExchanges.stateBidObjects[price] = bidObject.deepCopy(db, self.MarkStateBidObjectDirty)
for price, bidObject := range te.stateBidObjects {
stateExchanges.stateBidObjects[price] = bidObject.deepCopy(db, te.MarkStateBidObjectDirty)
}
for price := range self.stateBidObjectsDirty {
for price := range te.stateBidObjectsDirty {
stateExchanges.stateBidObjectsDirty[price] = struct{}{}
}
for price, askObject := range self.stateAskObjects {
stateExchanges.stateAskObjects[price] = askObject.deepCopy(db, self.MarkStateAskObjectDirty)
for price, askObject := range te.stateAskObjects {
stateExchanges.stateAskObjects[price] = askObject.deepCopy(db, te.MarkStateAskObjectDirty)
}
for price := range self.stateAskObjectsDirty {
for price := range te.stateAskObjectsDirty {
stateExchanges.stateAskObjectsDirty[price] = struct{}{}
}
for orderId, orderItem := range self.stateOrderObjects {
stateExchanges.stateOrderObjects[orderId] = orderItem.deepCopy(self.MarkStateOrderObjectDirty)
for orderId, orderItem := range te.stateOrderObjects {
stateExchanges.stateOrderObjects[orderId] = orderItem.deepCopy(te.MarkStateOrderObjectDirty)
}
for orderId := range self.stateOrderObjectsDirty {
for orderId := range te.stateOrderObjectsDirty {
stateExchanges.stateOrderObjectsDirty[orderId] = struct{}{}
}
for price, liquidationPrice := range self.liquidationPriceStates {
stateExchanges.liquidationPriceStates[price] = liquidationPrice.deepCopy(db, self.MarkStateLiquidationPriceDirty)
for price, liquidationPrice := range te.liquidationPriceStates {
stateExchanges.liquidationPriceStates[price] = liquidationPrice.deepCopy(db, te.MarkStateLiquidationPriceDirty)
}
for price := range self.liquidationPriceStatesDirty {
for price := range te.liquidationPriceStatesDirty {
stateExchanges.liquidationPriceStatesDirty[price] = struct{}{}
}
return stateExchanges
}
// Returns the address of the contract/orderId
func (c *tradingExchanges) Hash() common.Hash {
return c.orderBookHash
func (te *tradingExchanges) Hash() common.Hash {
return te.orderBookHash
}
func (self *tradingExchanges) SetNonce(nonce uint64) {
self.setNonce(nonce)
func (te *tradingExchanges) SetNonce(nonce uint64) {
te.setNonce(nonce)
}
func (self *tradingExchanges) setNonce(nonce uint64) {
self.data.Nonce = nonce
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) setNonce(nonce uint64) {
te.data.Nonce = nonce
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
func (self *tradingExchanges) Nonce() uint64 {
return self.data.Nonce
func (te *tradingExchanges) Nonce() uint64 {
return te.data.Nonce
}
func (self *tradingExchanges) setLastPrice(price *big.Int) {
self.data.LastPrice = price
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) setLastPrice(price *big.Int) {
te.data.LastPrice = price
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
func (self *tradingExchanges) setMediumPriceBeforeEpoch(price *big.Int) {
self.data.MediumPriceBeforeEpoch = price
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) setMediumPriceBeforeEpoch(price *big.Int) {
te.data.MediumPriceBeforeEpoch = price
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
func (self *tradingExchanges) setMediumPrice(price *big.Int, quantity *big.Int) {
self.data.MediumPrice = price
self.data.TotalQuantity = quantity
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) setMediumPrice(price *big.Int, quantity *big.Int) {
te.data.MediumPrice = price
te.data.TotalQuantity = quantity
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
// updateStateExchangeObject writes the given object to the trie.
func (self *tradingExchanges) removeStateOrderListAskObject(db Database, stateOrderList *stateOrderList) {
self.setError(self.asksTrie.TryDelete(stateOrderList.price[:]))
func (te *tradingExchanges) removeStateOrderListAskObject(db Database, stateOrderList *stateOrderList) {
te.setError(te.asksTrie.TryDelete(stateOrderList.price[:]))
}
// updateStateExchangeObject writes the given object to the trie.
func (self *tradingExchanges) removeStateOrderListBidObject(db Database, stateOrderList *stateOrderList) {
self.setError(self.bidsTrie.TryDelete(stateOrderList.price[:]))
func (te *tradingExchanges) removeStateOrderListBidObject(db Database, stateOrderList *stateOrderList) {
te.setError(te.bidsTrie.TryDelete(stateOrderList.price[:]))
}
// 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.
if obj := self.stateAskObjects[price]; obj != nil {
if obj := te.stateAskObjects[price]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.getAsksTrie(db).TryGet(price[:])
enc, err := te.getAsksTrie(db).TryGet(price[:])
if len(enc) == 0 {
self.setError(err)
te.setError(err)
return nil
}
var data orderList
@ -435,50 +435,50 @@ func (self *tradingExchanges) getStateOrderListAskObject(db Database, price comm
return nil
}
// Insert into the live set.
obj := newStateOrderList(self.db, Bid, self.orderBookHash, price, data, self.MarkStateAskObjectDirty)
self.stateAskObjects[price] = obj
obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateAskObjectDirty)
te.stateAskObjects[price] = obj
return obj
}
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateAskObjectDirty(price common.Hash) {
self.stateAskObjectsDirty[price] = struct{}{}
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) MarkStateAskObjectDirty(price common.Hash) {
te.stateAskObjectsDirty[price] = struct{}{}
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
// 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.
func (self *tradingExchanges) createStateOrderListAskObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(self.db, Ask, self.orderBookHash, price, orderList{Volume: Zero}, self.MarkStateAskObjectDirty)
self.stateAskObjects[price] = newobj
self.stateAskObjectsDirty[price] = struct{}{}
func (te *tradingExchanges) createStateOrderListAskObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(te.db, Ask, te.orderBookHash, price, orderList{Volume: Zero}, te.MarkStateAskObjectDirty)
te.stateAskObjects[price] = newobj
te.stateAskObjectsDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj)
if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
}
self.setError(self.asksTrie.TryUpdate(price[:], data))
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
te.setError(te.asksTrie.TryUpdate(price[:], data))
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
return newobj
}
// 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.
if obj := self.stateBidObjects[price]; obj != nil {
if obj := te.stateBidObjects[price]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.getBidsTrie(db).TryGet(price[:])
enc, err := te.getBidsTrie(db).TryGet(price[:])
if len(enc) == 0 {
self.setError(err)
te.setError(err)
return nil
}
var data orderList
@ -487,50 +487,50 @@ func (self *tradingExchanges) getStateBidOrderListObject(db Database, price comm
return nil
}
// Insert into the live set.
obj := newStateOrderList(self.db, Bid, self.orderBookHash, price, data, self.MarkStateBidObjectDirty)
self.stateBidObjects[price] = obj
obj := newStateOrderList(te.db, Bid, te.orderBookHash, price, data, te.MarkStateBidObjectDirty)
te.stateBidObjects[price] = obj
return obj
}
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateBidObjectDirty(price common.Hash) {
self.stateBidObjectsDirty[price] = struct{}{}
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) MarkStateBidObjectDirty(price common.Hash) {
te.stateBidObjectsDirty[price] = struct{}{}
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
// 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.
func (self *tradingExchanges) createStateBidOrderListObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(self.db, Bid, self.orderBookHash, price, orderList{Volume: Zero}, self.MarkStateBidObjectDirty)
self.stateBidObjects[price] = newobj
self.stateBidObjectsDirty[price] = struct{}{}
func (te *tradingExchanges) createStateBidOrderListObject(db Database, price common.Hash) (newobj *stateOrderList) {
newobj = newStateOrderList(te.db, Bid, te.orderBookHash, price, orderList{Volume: Zero}, te.MarkStateBidObjectDirty)
te.stateBidObjects[price] = newobj
te.stateBidObjectsDirty[price] = struct{}{}
data, err := rlp.EncodeToBytes(newobj)
if err != nil {
panic(fmt.Errorf("can't encode order list object at %x: %v", price[:], err))
}
self.setError(self.bidsTrie.TryUpdate(price[:], data))
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
te.setError(te.bidsTrie.TryUpdate(price[:], data))
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
return newobj
}
// 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.
if obj := self.stateOrderObjects[orderId]; obj != nil {
if obj := te.stateOrderObjects[orderId]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.getOrdersTrie(db).TryGet(orderId[:])
enc, err := te.getOrdersTrie(db).TryGet(orderId[:])
if len(enc) == 0 {
self.setError(err)
te.setError(err)
return nil
}
var data OrderItem
@ -539,48 +539,48 @@ func (self *tradingExchanges) getStateOrderObject(db Database, orderId common.Ha
return nil
}
// Insert into the live set.
obj := newStateOrderItem(self.orderBookHash, orderId, data, self.MarkStateOrderObjectDirty)
self.stateOrderObjects[orderId] = obj
obj := newStateOrderItem(te.orderBookHash, orderId, data, te.MarkStateOrderObjectDirty)
te.stateOrderObjects[orderId] = obj
return obj
}
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *tradingExchanges) MarkStateOrderObjectDirty(orderId common.Hash) {
self.stateOrderObjectsDirty[orderId] = struct{}{}
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (te *tradingExchanges) MarkStateOrderObjectDirty(orderId common.Hash) {
te.stateOrderObjectsDirty[orderId] = struct{}{}
if te.onDirty != nil {
te.onDirty(te.Hash())
te.onDirty = nil
}
}
// 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.
func (self *tradingExchanges) createStateOrderObject(db Database, orderId common.Hash, order OrderItem) (newobj *stateOrderItem) {
newobj = newStateOrderItem(self.orderBookHash, orderId, order, self.MarkStateOrderObjectDirty)
func (t *tradingExchanges) createStateOrderObject(db Database, orderId common.Hash, order OrderItem) (newobj *stateOrderItem) {
newobj = newStateOrderItem(t.orderBookHash, orderId, order, t.MarkStateOrderObjectDirty)
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.OrderID))
self.stateOrderObjects[orderIdHash] = newobj
self.stateOrderObjectsDirty[orderIdHash] = struct{}{}
if self.onDirty != nil {
self.onDirty(self.orderBookHash)
self.onDirty = nil
t.stateOrderObjects[orderIdHash] = newobj
t.stateOrderObjectsDirty[orderIdHash] = struct{}{}
if t.onDirty != nil {
t.onDirty(t.orderBookHash)
t.onDirty = nil
}
return newobj
}
// updateAskTrie writes cached storage modifications into the object's storage trie.
func (self *tradingExchanges) updateOrdersTrie(db Database) Trie {
tr := self.getOrdersTrie(db)
for orderId, orderItem := range self.stateOrderObjects {
if _, isDirty := self.stateOrderObjectsDirty[orderId]; isDirty {
delete(self.stateOrderObjectsDirty, orderId)
func (t *tradingExchanges) updateOrdersTrie(db Database) Trie {
tr := t.getOrdersTrie(db)
for orderId, orderItem := range t.stateOrderObjects {
if _, isDirty := t.stateOrderObjectsDirty[orderId]; isDirty {
delete(t.stateOrderObjectsDirty, orderId)
if orderItem.empty() {
self.setError(tr.TryDelete(orderId[:]))
t.setError(tr.TryDelete(orderId[:]))
continue
}
// Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(orderItem)
self.setError(tr.TryUpdate(orderId[:], v))
t.setError(tr.TryUpdate(orderId[:], v))
}
}
return tr
@ -588,71 +588,71 @@ func (self *tradingExchanges) updateOrdersTrie(db Database) Trie {
// CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root.
func (self *tradingExchanges) updateOrdersRoot(db Database) {
self.updateOrdersTrie(db)
self.data.OrderRoot = self.ordersTrie.Hash()
func (t *tradingExchanges) updateOrdersRoot(db Database) {
t.updateOrdersTrie(db)
t.data.OrderRoot = t.ordersTrie.Hash()
}
// CommitAskTrie the storage trie of the object to dwb.
// This updates the trie root.
func (self *tradingExchanges) CommitOrdersTrie(db Database) error {
self.updateOrdersTrie(db)
if self.dbErr != nil {
return self.dbErr
func (t *tradingExchanges) CommitOrdersTrie(db Database) error {
t.updateOrdersTrie(db)
if t.dbErr != nil {
return t.dbErr
}
root, err := self.ordersTrie.Commit(nil)
root, err := t.ordersTrie.Commit(nil)
if err == nil {
self.data.OrderRoot = root
t.data.OrderRoot = root
}
return err
}
func (self *tradingExchanges) MarkStateLiquidationPriceDirty(price common.Hash) {
self.liquidationPriceStatesDirty[price] = struct{}{}
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
func (t *tradingExchanges) MarkStateLiquidationPriceDirty(price common.Hash) {
t.liquidationPriceStatesDirty[price] = struct{}{}
if t.onDirty != nil {
t.onDirty(t.Hash())
t.onDirty = nil
}
}
func (self *tradingExchanges) createStateLiquidationPrice(db Database, liquidationPrice common.Hash) (newobj *liquidationPriceState) {
newobj = newLiquidationPriceState(self.db, self.orderBookHash, liquidationPrice, orderList{Volume: Zero}, self.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[liquidationPrice] = newobj
self.liquidationPriceStatesDirty[liquidationPrice] = struct{}{}
func (t *tradingExchanges) createStateLiquidationPrice(db Database, liquidationPrice common.Hash) (newobj *liquidationPriceState) {
newobj = newLiquidationPriceState(t.db, t.orderBookHash, liquidationPrice, orderList{Volume: Zero}, t.MarkStateLiquidationPriceDirty)
t.liquidationPriceStates[liquidationPrice] = newobj
t.liquidationPriceStatesDirty[liquidationPrice] = struct{}{}
data, err := rlp.EncodeToBytes(newobj)
if err != nil {
panic(fmt.Errorf("can't encode liquidation price object at %x: %v", liquidationPrice[:], err))
}
self.setError(self.getLiquidationPriceTrie(db).TryUpdate(liquidationPrice[:], data))
if self.onDirty != nil {
self.onDirty(self.Hash())
self.onDirty = nil
t.setError(t.getLiquidationPriceTrie(db).TryUpdate(liquidationPrice[:], data))
if t.onDirty != nil {
t.onDirty(t.Hash())
t.onDirty = nil
}
return newobj
}
func (self *tradingExchanges) getLiquidationPriceTrie(db Database) Trie {
if self.liquidationPriceTrie == nil {
func (t *tradingExchanges) getLiquidationPriceTrie(db Database) Trie {
if t.liquidationPriceTrie == nil {
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 {
self.liquidationPriceTrie, _ = db.OpenStorageTrie(self.orderBookHash, EmptyHash)
self.setError(fmt.Errorf("can't create liquidation liquidationPrice trie: %v", err))
t.liquidationPriceTrie, _ = db.OpenStorageTrie(t.orderBookHash, EmptyHash)
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.
if obj := self.liquidationPriceStates[price]; obj != nil {
if obj := t.liquidationPriceStates[price]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.getLiquidationPriceTrie(db).TryGet(price[:])
enc, err := t.getLiquidationPriceTrie(db).TryGet(price[:])
if len(enc) == 0 {
self.setError(err)
t.setError(err)
return nil
}
var data orderList
@ -661,16 +661,16 @@ func (self *tradingExchanges) getStateLiquidationPrice(db Database, price common
return nil
}
// Insert into the live set.
obj := newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj
obj := newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
t.liquidationPriceStates[price] = obj
return obj
}
func (self *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := self.getLiquidationPriceTrie(db)
func (t *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := t.getLiquidationPriceTrie(db)
encKey, encValue, err := trie.TryGetBestLeftKeyAndValue()
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
}
if len(encKey) == 0 || len(encValue) == 0 {
@ -678,25 +678,25 @@ func (self *tradingExchanges) getLowestLiquidationPrice(db Database) (common.Has
return EmptyHash, nil
}
price := common.BytesToHash(encKey)
obj := self.liquidationPriceStates[price]
obj := t.liquidationPriceStates[price]
if obj == nil {
var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash, nil
}
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj
obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
t.liquidationPriceStates[price] = obj
}
return price, obj
}
func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit common.Hash) map[common.Hash]*liquidationPriceState {
trie := self.getLiquidationPriceTrie(db)
func (t *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit common.Hash) map[common.Hash]*liquidationPriceState {
trie := t.getLiquidationPriceTrie(db)
encKeys, encValues, err := trie.TryGetAllLeftKeyAndValue(limit.Bytes())
result := map[common.Hash]*liquidationPriceState{}
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
}
if len(encKeys) == 0 || len(encValues) == 0 {
@ -705,15 +705,15 @@ func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit com
}
for i := range encKeys {
price := common.BytesToHash(encKeys[i])
obj := self.liquidationPriceStates[price]
obj := t.liquidationPriceStates[price]
if obj == nil {
var data orderList
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)
return result
}
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj
obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
t.liquidationPriceStates[price] = obj
}
if obj.empty() {
continue
@ -723,11 +723,11 @@ func (self *tradingExchanges) getAllLowerLiquidationPrice(db Database, limit com
return result
}
func (self *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := self.getLiquidationPriceTrie(db)
func (t *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Hash, *liquidationPriceState) {
trie := t.getLiquidationPriceTrie(db)
encKey, encValue, err := trie.TryGetBestRightKeyAndValue()
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
}
if len(encKey) == 0 || len(encValue) == 0 {
@ -735,28 +735,29 @@ func (self *tradingExchanges) getHighestLiquidationPrice(db Database) (common.Ha
return EmptyHash, nil
}
price := common.BytesToHash(encKey)
obj := self.liquidationPriceStates[price]
obj := t.liquidationPriceStates[price]
if obj == nil {
var data orderList
if err := rlp.DecodeBytes(encValue, &data); err != nil {
log.Error("Failed to decode state get best ask trie", "err", err)
return EmptyHash, nil
}
obj = newLiquidationPriceState(self.db, self.orderBookHash, price, data, self.MarkStateLiquidationPriceDirty)
self.liquidationPriceStates[price] = obj
obj = newLiquidationPriceState(t.db, t.orderBookHash, price, data, t.MarkStateLiquidationPriceDirty)
t.liquidationPriceStates[price] = obj
}
if obj.empty() {
return EmptyHash, nil
}
return price, obj
}
func (self *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
tr := self.getLiquidationPriceTrie(db)
for price, stateObject := range self.liquidationPriceStates {
if _, isDirty := self.liquidationPriceStatesDirty[price]; isDirty {
delete(self.liquidationPriceStatesDirty, price)
func (t *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
tr := t.getLiquidationPriceTrie(db)
for price, stateObject := range t.liquidationPriceStates {
if _, isDirty := t.liquidationPriceStatesDirty[price]; isDirty {
delete(t.liquidationPriceStatesDirty, price)
if stateObject.empty() {
self.setError(tr.TryDelete(price[:]))
t.setError(tr.TryDelete(price[:]))
continue
}
err := stateObject.updateRoot(db)
@ -765,23 +766,23 @@ func (self *tradingExchanges) updateLiquidationPriceTrie(db Database) Trie {
}
// Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(stateObject)
self.setError(tr.TryUpdate(price[:], v))
t.setError(tr.TryUpdate(price[:], v))
}
}
return tr
}
func (self *tradingExchanges) updateLiquidationPriceRoot(db Database) {
self.updateLiquidationPriceTrie(db)
self.data.LiquidationPriceRoot = self.liquidationPriceTrie.Hash()
func (t *tradingExchanges) updateLiquidationPriceRoot(db Database) {
t.updateLiquidationPriceTrie(db)
t.data.LiquidationPriceRoot = t.liquidationPriceTrie.Hash()
}
func (self *tradingExchanges) CommitLiquidationPriceTrie(db Database) error {
self.updateLiquidationPriceTrie(db)
if self.dbErr != nil {
return self.dbErr
func (t *tradingExchanges) CommitLiquidationPriceTrie(db Database) error {
t.updateLiquidationPriceTrie(db)
if t.dbErr != nil {
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
if err := rlp.DecodeBytes(leaf, &orderList); err != nil {
return nil
@ -792,23 +793,23 @@ func (self *tradingExchanges) CommitLiquidationPriceTrie(db Database) error {
return nil
})
if err == nil {
self.data.LiquidationPriceRoot = root
t.data.LiquidationPriceRoot = root
}
return err
}
func (c *tradingExchanges) addLendingCount(amount *big.Int) {
c.setLendingCount(new(big.Int).Add(c.data.LendingCount, amount))
func (t *tradingExchanges) addLendingCount(amount *big.Int) {
t.setLendingCount(new(big.Int).Add(t.data.LendingCount, amount))
}
func (c *tradingExchanges) subLendingCount(amount *big.Int) {
c.setLendingCount(new(big.Int).Sub(c.data.LendingCount, amount))
func (t *tradingExchanges) subLendingCount(amount *big.Int) {
t.setLendingCount(new(big.Int).Sub(t.data.LendingCount, amount))
}
func (self *tradingExchanges) setLendingCount(volume *big.Int) {
self.data.LendingCount = volume
if self.onDirty != nil {
self.onDirty(self.orderBookHash)
self.onDirty = nil
func (t *tradingExchanges) setLendingCount(volume *big.Int) {
t.data.LendingCount = volume
if t.onDirty != nil {
t.onDirty(t.orderBookHash)
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.
func (self *TradingStateDB) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
func (t *TradingStateDB) setError(err error) {
if t.dbErr == nil {
t.dbErr = err
}
}
func (self *TradingStateDB) Error() error {
return self.dbErr
func (t *TradingStateDB) Error() error {
return t.dbErr
}
// Exist reports whether the given orderId address exists in the state.
// Notably this also returns true for suicided exchanges.
func (self *TradingStateDB) Exist(addr common.Hash) bool {
return self.getStateExchangeObject(addr) != nil
func (t *TradingStateDB) Exist(addr common.Hash) bool {
return t.getStateExchangeObject(addr) != nil
}
// Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *TradingStateDB) Empty(addr common.Hash) bool {
so := self.getStateExchangeObject(addr)
func (t *TradingStateDB) Empty(addr common.Hash) bool {
so := t.getStateExchangeObject(addr)
return so == nil || so.empty()
}
func (self *TradingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := self.getStateExchangeObject(addr)
func (t *TradingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := t.getStateExchangeObject(addr)
if stateObject != nil {
return stateObject.Nonce()
}
return 0
}
func (self *TradingStateDB) GetLastPrice(addr common.Hash) *big.Int {
stateObject := self.getStateExchangeObject(addr)
func (t *TradingStateDB) GetLastPrice(addr common.Hash) *big.Int {
stateObject := t.getStateExchangeObject(addr)
if stateObject != nil {
return stateObject.data.LastPrice
}
return nil
}
func (self *TradingStateDB) GetMediumPriceBeforeEpoch(addr common.Hash) *big.Int {
stateObject := self.getStateExchangeObject(addr)
func (t *TradingStateDB) GetMediumPriceBeforeEpoch(addr common.Hash) *big.Int {
stateObject := t.getStateExchangeObject(addr)
if stateObject != nil {
return stateObject.data.MediumPriceBeforeEpoch
}
return Zero
}
func (self *TradingStateDB) GetMediumPriceAndTotalAmount(addr common.Hash) (*big.Int, *big.Int) {
stateObject := self.getStateExchangeObject(addr)
func (t *TradingStateDB) GetMediumPriceAndTotalAmount(addr common.Hash) (*big.Int, *big.Int) {
stateObject := t.getStateExchangeObject(addr)
if stateObject != nil {
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.
func (self *TradingStateDB) Database() Database {
return self.db
func (t *TradingStateDB) Database() Database {
return t.db
}
func (self *TradingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := self.GetOrNewStateExchangeObject(addr)
func (t *TradingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, nonceChange{
t.journal = append(t.journal, nonceChange{
hash: addr,
prev: self.GetNonce(addr),
prev: t.GetNonce(addr),
})
stateObject.SetNonce(nonce)
}
}
func (self *TradingStateDB) SetLastPrice(addr common.Hash, price *big.Int) {
stateObject := self.GetOrNewStateExchangeObject(addr)
func (t *TradingStateDB) SetLastPrice(addr common.Hash, price *big.Int) {
stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, lastPriceChange{
t.journal = append(t.journal, lastPriceChange{
hash: addr,
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) {
stateObject := self.GetOrNewStateExchangeObject(addr)
func (t *TradingStateDB) SetMediumPrice(addr common.Hash, price *big.Int, quantity *big.Int) {
stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, mediumPriceChange{
t.journal = append(t.journal, mediumPriceChange{
hash: addr,
prevPrice: stateObject.data.MediumPrice,
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) {
stateObject := self.GetOrNewStateExchangeObject(addr)
func (t *TradingStateDB) SetMediumPriceBeforeEpoch(addr common.Hash, price *big.Int) {
stateObject := t.GetOrNewStateExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, mediumPriceBeforeEpochChange{
t.journal = append(t.journal, mediumPriceBeforeEpochChange{
hash: addr,
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)
stateExchange := self.getStateExchangeObject(orderBook)
stateExchange := t.getStateExchangeObject(orderBook)
if stateExchange == nil {
stateExchange = self.createExchangeObject(orderBook)
stateExchange = t.createExchangeObject(orderBook)
}
var stateOrderList *stateOrderList
switch order.Side {
case Ask:
stateOrderList = stateExchange.getStateOrderListAskObject(self.db, priceHash)
stateOrderList = stateExchange.getStateOrderListAskObject(t.db, priceHash)
if stateOrderList == nil {
stateOrderList = stateExchange.createStateOrderListAskObject(self.db, priceHash)
stateOrderList = stateExchange.createStateOrderListAskObject(t.db, priceHash)
}
case Bid:
stateOrderList = stateExchange.getStateBidOrderListObject(self.db, priceHash)
stateOrderList = stateExchange.getStateBidOrderListObject(t.db, priceHash)
if stateOrderList == nil {
stateOrderList = stateExchange.createStateBidOrderListObject(self.db, priceHash)
stateOrderList = stateExchange.createStateBidOrderListObject(t.db, priceHash)
}
default:
return
}
self.journal = append(self.journal, insertOrder{
t.journal = append(t.journal, insertOrder{
orderBook: orderBook,
orderId: orderId,
order: &order,
})
stateExchange.createStateOrderObject(self.db, orderId, order)
stateOrderList.insertOrderItem(self.db, orderId, common.BigToHash(order.Quantity))
stateExchange.createStateOrderObject(t.db, orderId, order)
stateOrderList.insertOrderItem(t.db, orderId, common.BigToHash(order.Quantity))
stateOrderList.AddVolume(order.Quantity)
}
func (self *TradingStateDB) GetOrder(orderBook common.Hash, orderId common.Hash) OrderItem {
stateObject := self.GetOrNewStateExchangeObject(orderBook)
func (t *TradingStateDB) GetOrder(orderBook common.Hash, orderId common.Hash) OrderItem {
stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject == nil {
return EmptyOrder
}
stateOrderItem := stateObject.getStateOrderObject(self.db, orderId)
stateOrderItem := stateObject.getStateOrderObject(t.db, orderId)
if stateOrderItem == nil {
return EmptyOrder
}
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)
stateObject := self.GetOrNewStateExchangeObject(orderBook)
stateObject := t.GetOrNewStateExchangeObject(orderBook)
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
switch side {
case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, priceHash)
stateOrderList = stateObject.getStateOrderListAskObject(t.db, priceHash)
case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, priceHash)
stateOrderList = stateObject.getStateBidOrderListObject(t.db, priceHash)
default:
return fmt.Errorf("Order type not found : %s ", side)
return fmt.Errorf("not found order type: %s", side)
}
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() {
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 {
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,
orderId: orderId,
order: self.GetOrder(orderBook, orderId),
order: t.GetOrder(orderBook, orderId),
amount: amount,
})
newAmount := new(big.Int).Sub(currentAmount, amount)
@ -262,86 +263,86 @@ func (self *TradingStateDB) SubAmountOrderItem(orderBook common.Hash, orderId co
stateOrderList.subVolume(amount)
stateOrderItem.setVolume(newAmount)
if newAmount.Sign() == 0 {
stateOrderList.removeOrderItem(self.db, orderId)
stateOrderList.removeOrderItem(t.db, orderId)
} else {
stateOrderList.setOrderItem(orderId, common.BigToHash(newAmount))
}
if stateOrderList.empty() {
switch side {
case Ask:
stateObject.removeStateOrderListAskObject(self.db, stateOrderList)
stateObject.removeStateOrderListAskObject(t.db, stateOrderList)
case Bid:
stateObject.removeStateOrderListBidObject(self.db, stateOrderList)
stateObject.removeStateOrderListBidObject(t.db, stateOrderList)
default:
}
}
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))
stateObject := self.GetOrNewStateExchangeObject(orderBook)
stateObject := t.GetOrNewStateExchangeObject(orderBook)
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() {
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)
var stateOrderList *stateOrderList
switch stateOrderItem.data.Side {
case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, priceHash)
stateOrderList = stateObject.getStateOrderListAskObject(t.db, priceHash)
case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, priceHash)
stateOrderList = stateObject.getStateBidOrderListObject(t.db, priceHash)
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() {
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 {
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 {
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 {
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,
orderId: orderIdHash,
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))
stateOrderList.subVolume(currentAmount)
stateOrderList.removeOrderItem(self.db, orderIdHash)
stateOrderList.removeOrderItem(t.db, orderIdHash)
if stateOrderList.empty() {
switch stateOrderItem.data.Side {
case Ask:
stateObject.removeStateOrderListAskObject(self.db, stateOrderList)
stateObject.removeStateOrderListAskObject(t.db, stateOrderList)
case Bid:
stateObject.removeStateOrderListBidObject(self.db, stateOrderList)
stateObject.removeStateOrderListBidObject(t.db, stateOrderList)
default:
}
}
return nil
}
func (self *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, orderType string) *big.Int {
stateObject := self.GetOrNewStateExchangeObject(orderBook)
func (t *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, orderType string) *big.Int {
stateObject := t.GetOrNewStateExchangeObject(orderBook)
var volume *big.Int = nil
if stateObject != nil {
var stateOrderList *stateOrderList
switch orderType {
case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, common.BigToHash(price))
stateOrderList = stateObject.getStateOrderListAskObject(t.db, common.BigToHash(price))
case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, common.BigToHash(price))
stateOrderList = stateObject.getStateBidOrderListObject(t.db, common.BigToHash(price))
default:
return Zero
}
@ -352,14 +353,15 @@ func (self *TradingStateDB) GetVolume(orderBook common.Hash, price *big.Int, ord
}
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 {
priceHash := stateObject.getBestPriceAsksTrie(self.db)
priceHash := stateObject.getBestPriceAsksTrie(t.db)
if common.EmptyHash(priceHash) {
return Zero, Zero
}
orderList := stateObject.getStateOrderListAskObject(self.db, priceHash)
orderList := stateObject.getStateOrderListAskObject(t.db, priceHash)
if orderList == nil {
log.Error("order list ask not found", "price", priceHash.Hex())
return Zero, Zero
@ -369,14 +371,14 @@ func (self *TradingStateDB) GetBestAskPrice(orderBook common.Hash) (*big.Int, *b
return Zero, Zero
}
func (self *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getStateExchangeObject(orderBook)
func (t *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := t.getStateExchangeObject(orderBook)
if stateObject != nil {
priceHash := stateObject.getBestBidsTrie(self.db)
priceHash := stateObject.getBestBidsTrie(t.db)
if common.EmptyHash(priceHash) {
return Zero, Zero
}
orderList := stateObject.getStateBidOrderListObject(self.db, priceHash)
orderList := stateObject.getStateBidOrderListObject(t.db, priceHash)
if orderList == nil {
log.Error("order list bid not found", "price", priceHash.Hex())
return Zero, Zero
@ -386,52 +388,52 @@ func (self *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *b
return Zero, Zero
}
func (self *TradingStateDB) GetBestOrderIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := self.GetOrNewStateExchangeObject(orderBook)
func (t *TradingStateDB) GetBestOrderIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := t.GetOrNewStateExchangeObject(orderBook)
if stateObject != nil {
var stateOrderList *stateOrderList
switch side {
case Ask:
stateOrderList = stateObject.getStateOrderListAskObject(self.db, common.BigToHash(price))
stateOrderList = stateObject.getStateOrderListAskObject(t.db, common.BigToHash(price))
case Bid:
stateOrderList = stateObject.getStateBidOrderListObject(self.db, common.BigToHash(price))
stateOrderList = stateObject.getStateBidOrderListObject(t.db, common.BigToHash(price))
default:
return EmptyHash, Zero, fmt.Errorf("not found side :%s ", side)
return EmptyHash, Zero, fmt.Errorf("not found side: %s", side)
}
if stateOrderList != nil {
key, _, err := stateOrderList.getTrie(self.db).TryGetBestLeftKeyAndValue()
key, _, err := stateOrderList.getTrie(t.db).TryGetBestLeftKeyAndValue()
if err != nil {
return EmptyHash, Zero, err
}
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 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.
func (self *TradingStateDB) updateStateExchangeObject(stateObject *tradingExchanges) {
func (t *TradingStateDB) updateStateExchangeObject(stateObject *tradingExchanges) {
addr := stateObject.Hash()
data, err := rlp.EncodeToBytes(stateObject)
if err != nil {
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.
func (self *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObject *tradingExchanges) {
func (t *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObject *tradingExchanges) {
// Prefer 'live' objects.
if obj := self.stateExhangeObjects[addr]; obj != nil {
if obj := t.stateExhangeObjects[addr]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.trie.TryGet(addr[:])
enc, err := t.trie.TryGet(addr[:])
if len(enc) == 0 {
self.setError(err)
t.setError(err)
return nil
}
var data tradingExchangeObject
@ -440,169 +442,169 @@ func (self *TradingStateDB) getStateExchangeObject(addr common.Hash) (stateObjec
return nil
}
// Insert into the live set.
obj := newStateExchanges(self, addr, data, self.MarkStateExchangeObjectDirty)
self.stateExhangeObjects[addr] = obj
obj := newStateExchanges(t, addr, data, t.MarkStateExchangeObjectDirty)
t.stateExhangeObjects[addr] = obj
return obj
}
func (self *TradingStateDB) setStateExchangeObject(object *tradingExchanges) {
self.stateExhangeObjects[object.Hash()] = object
self.stateExhangeObjectsDirty[object.Hash()] = struct{}{}
func (t *TradingStateDB) setStateExchangeObject(object *tradingExchanges) {
t.stateExhangeObjects[object.Hash()] = object
t.stateExhangeObjectsDirty[object.Hash()] = struct{}{}
}
// Retrieve a state object or create a new state object if nil.
func (self *TradingStateDB) GetOrNewStateExchangeObject(addr common.Hash) *tradingExchanges {
stateExchangeObject := self.getStateExchangeObject(addr)
func (t *TradingStateDB) GetOrNewStateExchangeObject(addr common.Hash) *tradingExchanges {
stateExchangeObject := t.getStateExchangeObject(addr)
if stateExchangeObject == nil {
stateExchangeObject = self.createExchangeObject(addr)
stateExchangeObject = t.createExchangeObject(addr)
}
return stateExchangeObject
}
// MarkStateAskObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *TradingStateDB) MarkStateExchangeObjectDirty(addr common.Hash) {
self.stateExhangeObjectsDirty[addr] = struct{}{}
func (t *TradingStateDB) MarkStateExchangeObjectDirty(addr common.Hash) {
t.stateExhangeObjectsDirty[addr] = struct{}{}
}
// 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.
func (self *TradingStateDB) createExchangeObject(hash common.Hash) (newobj *tradingExchanges) {
newobj = newStateExchanges(self, hash, tradingExchangeObject{LendingCount: Zero, MediumPrice: Zero, MediumPriceBeforeEpoch: Zero, TotalQuantity: Zero}, self.MarkStateExchangeObjectDirty)
func (t *TradingStateDB) createExchangeObject(hash common.Hash) (newobj *tradingExchanges) {
newobj = newStateExchanges(t, hash, tradingExchangeObject{LendingCount: Zero, MediumPrice: Zero, MediumPriceBeforeEpoch: Zero, TotalQuantity: Zero}, t.MarkStateExchangeObjectDirty)
newobj.setNonce(0) // sets the object to dirty
self.setStateExchangeObject(newobj)
t.setStateExchangeObject(newobj)
return newobj
}
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func (self *TradingStateDB) Copy() *TradingStateDB {
self.lock.Lock()
defer self.lock.Unlock()
func (t *TradingStateDB) Copy() *TradingStateDB {
t.lock.Lock()
defer t.lock.Unlock()
// Copy all the basic fields, initialize the memory ones
state := &TradingStateDB{
db: self.db,
trie: self.db.CopyTrie(self.trie),
stateExhangeObjects: make(map[common.Hash]*tradingExchanges, len(self.stateExhangeObjectsDirty)),
stateExhangeObjectsDirty: make(map[common.Hash]struct{}, len(self.stateExhangeObjectsDirty)),
db: t.db,
trie: t.db.CopyTrie(t.trie),
stateExhangeObjects: make(map[common.Hash]*tradingExchanges, len(t.stateExhangeObjectsDirty)),
stateExhangeObjectsDirty: make(map[common.Hash]struct{}, len(t.stateExhangeObjectsDirty)),
}
// Copy the dirty states, logs, and preimages
for addr := range self.stateExhangeObjectsDirty {
for addr := range t.stateExhangeObjectsDirty {
state.stateExhangeObjectsDirty[addr] = struct{}{}
}
for addr, exchangeObject := range self.stateExhangeObjects {
for addr, exchangeObject := range t.stateExhangeObjects {
state.stateExhangeObjects[addr] = exchangeObject.deepCopy(state, state.MarkStateExchangeObjectDirty)
}
return state
}
func (s *TradingStateDB) clearJournalAndRefund() {
s.journal = nil
s.validRevisions = s.validRevisions[:0]
func (t *TradingStateDB) clearJournalAndRefund() {
t.journal = nil
t.validRevisions = t.validRevisions[:0]
}
// Snapshot returns an identifier for the current revision of the state.
func (self *TradingStateDB) Snapshot() int {
id := self.nextRevisionId
self.nextRevisionId++
self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)})
func (t *TradingStateDB) Snapshot() int {
id := t.nextRevisionId
t.nextRevisionId++
t.validRevisions = append(t.validRevisions, revision{id, len(t.journal)})
return id
}
// 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.
idx := sort.Search(len(self.validRevisions), func(i int) bool {
return self.validRevisions[i].id >= revid
idx := sort.Search(len(t.validRevisions), func(i int) bool {
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))
}
snapshot := self.validRevisions[idx].journalIndex
snapshot := t.validRevisions[idx].journalIndex
// Replay the journal to undo changes.
for i := len(self.journal) - 1; i >= snapshot; i-- {
self.journal[i].undo(self)
for i := len(t.journal) - 1; i >= snapshot; i-- {
t.journal[i].undo(t)
}
self.journal = self.journal[:snapshot]
t.journal = t.journal[:snapshot]
// 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
// and clears the journal as well as the refunds.
func (s *TradingStateDB) Finalise() {
func (t *TradingStateDB) Finalise() {
// Commit objects to the trie.
for addr, stateObject := range s.stateExhangeObjects {
if _, isDirty := s.stateExhangeObjectsDirty[addr]; isDirty {
for addr, stateObject := range t.stateExhangeObjects {
if _, isDirty := t.stateExhangeObjectsDirty[addr]; isDirty {
// 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 {
log.Warn("Finalise updateAsksRoot", "err", err, "addr", addr, "stateObject", *stateObject)
}
stateObject.updateBidsRoot(s.db)
stateObject.updateOrdersRoot(s.db)
stateObject.updateLiquidationPriceRoot(s.db)
stateObject.updateBidsRoot(t.db)
stateObject.updateOrdersRoot(t.db)
stateObject.updateLiquidationPriceRoot(t.db)
// Update the object in the main orderId trie.
s.updateStateExchangeObject(stateObject)
t.updateStateExchangeObject(stateObject)
//delete(s.stateExhangeObjectsDirty, addr)
}
}
s.clearJournalAndRefund()
t.clearJournalAndRefund()
}
// IntermediateRoot computes the current root orderBookHash of the state trie.
// It is called in between transactions to get the root orderBookHash that
// goes into transaction receipts.
func (s *TradingStateDB) IntermediateRoot() common.Hash {
s.Finalise()
return s.trie.Hash()
func (t *TradingStateDB) IntermediateRoot() common.Hash {
t.Finalise()
return t.trie.Hash()
}
// Commit writes the state to the underlying in-memory trie database.
func (s *TradingStateDB) Commit() (root common.Hash, err error) {
defer s.clearJournalAndRefund()
func (t *TradingStateDB) Commit() (root common.Hash, err error) {
defer t.clearJournalAndRefund()
// Commit objects to the trie.
for addr, stateObject := range s.stateExhangeObjects {
if _, isDirty := s.stateExhangeObjectsDirty[addr]; isDirty {
for addr, stateObject := range t.stateExhangeObjects {
if _, isDirty := t.stateExhangeObjectsDirty[addr]; isDirty {
// 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
}
if err := stateObject.CommitBidsTrie(s.db); err != nil {
if err := stateObject.CommitBidsTrie(t.db); err != nil {
return EmptyHash, err
}
if err := stateObject.CommitOrdersTrie(s.db); err != nil {
if err := stateObject.CommitOrdersTrie(t.db); err != nil {
return EmptyHash, err
}
if err := stateObject.CommitLiquidationPriceTrie(s.db); err != nil {
if err := stateObject.CommitLiquidationPriceTrie(t.db); err != nil {
return EmptyHash, err
}
// Update the object in the main orderId trie.
s.updateStateExchangeObject(stateObject)
delete(s.stateExhangeObjectsDirty, addr)
t.updateStateExchangeObject(stateObject)
delete(t.stateExhangeObjectsDirty, addr)
}
}
// 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
if err := rlp.DecodeBytes(leaf, &exchange); err != nil {
return nil
}
if exchange.AskRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.AskRoot, parent)
t.db.TrieDB().Reference(exchange.AskRoot, parent)
}
if exchange.BidRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.BidRoot, parent)
t.db.TrieDB().Reference(exchange.BidRoot, parent)
}
if exchange.OrderRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.OrderRoot, parent)
t.db.TrieDB().Reference(exchange.OrderRoot, parent)
}
if exchange.LiquidationPriceRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LiquidationPriceRoot, parent)
t.db.TrieDB().Reference(exchange.LiquidationPriceRoot, parent)
}
return nil
})
@ -610,19 +612,19 @@ func (s *TradingStateDB) Commit() (root common.Hash, err error) {
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{}
orderbookState := self.getStateExchangeObject(orderBook)
orderbookState := t.getStateExchangeObject(orderBook)
if orderbookState == nil {
return result
}
mapPrices := orderbookState.getAllLowerLiquidationPrice(self.db, common.BigToHash(limit))
mapPrices := orderbookState.getAllLowerLiquidationPrice(t.db, common.BigToHash(limit))
for priceHash, liquidationState := range mapPrices {
price := new(big.Int).SetBytes(priceHash[:])
log.Debug("GetAllLowerLiquidationPriceData", "price", price, "limit", limit)
if liquidationState != nil && price.Sign() > 0 && price.Cmp(limit) < 0 {
liquidationData := map[common.Hash][]common.Hash{}
priceLiquidationData := liquidationState.getAllLiquidationData(self.db)
priceLiquidationData := liquidationState.getAllLiquidationData(t.db)
for lendingBook, data := range priceLiquidationData {
if len(data) == 0 {
continue
@ -641,16 +643,16 @@ func (self *TradingStateDB) GetAllLowerLiquidationPriceData(orderBook common.Has
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{}
orderbookState := self.getStateExchangeObject(orderBook)
orderbookState := t.getStateExchangeObject(orderBook)
if orderbookState == nil {
return common.Big0, liquidationData
}
highestPriceHash, liquidationState := orderbookState.getHighestLiquidationPrice(self.db)
highestPriceHash, liquidationState := orderbookState.getHighestLiquidationPrice(t.db)
highestPrice := new(big.Int).SetBytes(highestPriceHash[:])
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 {
if len(data) == 0 {
continue
@ -667,26 +669,26 @@ func (self *TradingStateDB) GetHighestLiquidationPriceData(orderBook common.Hash
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)
priceHash := common.BigToHash(price)
orderBookState := self.getStateExchangeObject(orderBook)
orderBookState := t.getStateExchangeObject(orderBook)
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 {
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 {
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)
liquidationPriceState.AddVolume(One)
orderBookState.addLendingCount(One)
self.journal = append(self.journal, insertLiquidationPrice{
t.journal = append(t.journal, insertLiquidationPrice{
orderBook: orderBook,
price: price,
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)
priceHash := common.BigToHash(price)
orderbookState := self.getStateExchangeObject(orderBook)
orderbookState := t.getStateExchangeObject(orderBook)
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 {
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 {
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) {
return fmt.Errorf("trade id not found : %s , %s ,%s , %d ", orderBook.Hex(), priceHash.Hex(), lendingBook.Hex(), tradeId)
if !lendingBookState.Exist(t.db, tradeIdHash) {
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)
liquidationPriceState.subVolume(One)
if liquidationPriceState.Volume().Sign() == 0 {
err := orderbookState.getLiquidationPriceTrie(self.db).TryDelete(priceHash[:])
err := orderbookState.getLiquidationPriceTrie(t.db).TryDelete(priceHash[:])
if err != nil {
log.Warn("RemoveLiquidationPrice getLiquidationPriceTrie.TryDelete", "err", err, "priceHash", priceHash[:])
}
}
orderbookState.subLendingCount(One)
self.journal = append(self.journal, removeLiquidationPrice{
t.journal = append(t.journal, removeLiquidationPrice{
orderBook: orderBook,
price: price,
lendingBook: lendingBook,

View file

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

View file

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

View file

@ -10,11 +10,11 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/globalsign/mgo"
"github.com/globalsign/mgo/bson"
lru "github.com/hashicorp/golang-lru"
)
const (
@ -32,7 +32,7 @@ type MongoDatabase struct {
Session *mgo.Session
dbName string
emptyKey []byte
cacheItems *lru.Cache // Cache for reading
cacheItems *lru.Cache[string, interface{}] // Cache for reading
orderBulk *mgo.Bulk
tradeBulk *mgo.Bulk
epochPriceBulk *mgo.Bulk
@ -64,12 +64,11 @@ func NewMongoDatabase(session *mgo.Session, dbName string, mongoURL string, repl
if cacheLimit > 0 {
itemCacheLimit = cacheLimit
}
cacheItems, _ := lru.New(itemCacheLimit)
db := &MongoDatabase{
Session: session,
dbName: dbName,
cacheItems: cacheItems,
cacheItems: lru.NewCache[string, interface{}](itemCacheLimit),
}
if err := db.EnsureIndexes(); err != nil {
return nil, err
@ -101,7 +100,7 @@ func (db *MongoDatabase) HasObject(hash common.Hash, val interface{}) (bool, err
err error
)
query := bson.M{"hash": hash.Hex()}
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
// Find key in ordersCollection collection
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:
// Find key in lendingItemsCollection collection
item := val.(*lendingstate.LendingItem)
switch item.Type {
case lendingstate.Repay:
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()}
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
var oi *tradingstate.OrderItem
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:
var li *lendingstate.LendingItem
var err error
item := val.(*lendingstate.LendingItem)
switch item.Type {
case lendingstate.Repay:
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())
db.cacheItems.Add(cacheKey, val)
switch val.(type) {
switch item := val.(type) {
case *tradingstate.Trade:
// PutObject trade into tradesCollection collection
db.tradeBulk.Insert(val.(*tradingstate.Trade))
db.tradeBulk.Insert(item)
case *tradingstate.OrderItem:
// PutObject order into ordersCollection collection
o := val.(*tradingstate.OrderItem)
if o.Status == tradingstate.OrderStatusOpen {
db.orderBulk.Insert(o)
if item.Status == tradingstate.OrderStatusOpen {
db.orderBulk.Insert(item)
} else {
query := bson.M{"hash": o.Hash.Hex()}
db.orderBulk.Upsert(query, o)
query := bson.M{"hash": item.Hash.Hex()}
db.orderBulk.Upsert(query, item)
}
return nil
case *tradingstate.EpochPriceItem:
item := val.(*tradingstate.EpochPriceItem)
query := bson.M{"hash": item.Hash.Hex()}
db.epochPriceBulk.Upsert(query, item)
return nil
case *lendingstate.LendingTrade:
lt := val.(*lendingstate.LendingTrade)
// PutObject LendingTrade into tradesCollection collection
if existed, err := db.HasObject(hash, val); err == nil && existed {
query := bson.M{"hash": lt.Hash.Hex()}
db.lendingTradeBulk.Upsert(query, lt)
query := bson.M{"hash": item.Hash.Hex()}
db.lendingTradeBulk.Upsert(query, item)
} else {
db.lendingTradeBulk.Insert(lt)
db.lendingTradeBulk.Insert(item)
}
case *lendingstate.LendingItem:
// PutObject order into ordersCollection collection
li := val.(*lendingstate.LendingItem)
switch li.Type {
switch item.Type {
case lendingstate.Repay:
if li.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.Repay
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.Repay
}
db.repayBulk.Insert(li)
db.repayBulk.Insert(item)
return nil
case lendingstate.TopUp:
if li.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.TopUp
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.TopUp
}
db.topUpBulk.Insert(li)
db.topUpBulk.Insert(item)
return nil
case lendingstate.Recall:
if li.Status != lendingstate.LendingStatusReject {
li.Status = lendingstate.Recall
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.Recall
}
db.recallBulk.Insert(li)
db.recallBulk.Insert(item)
return nil
default:
if li.Status == lendingstate.LendingStatusOpen {
db.lendingItemBulk.Insert(li)
if item.Status == lendingstate.LendingStatusOpen {
db.lendingItemBulk.Insert(item)
} else {
query := bson.M{"hash": li.Hash.Hex()}
db.lendingItemBulk.Upsert(query, li)
query := bson.M{"hash": item.Hash.Hex()}
db.lendingItemBulk.Upsert(query, item)
}
return nil
}
@ -313,7 +306,7 @@ func (db *MongoDatabase) DeleteObject(hash common.Hash, val interface{}) error {
if found {
var err error
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
err = sc.DB(db.dbName).C(ordersCollection).Remove(query)
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)
}
case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
switch item.Type {
case lendingstate.Repay:
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()
query := bson.M{"txHash": txhash.Hex()}
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
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)
@ -434,7 +426,6 @@ func (db *MongoDatabase) DeleteItemByTxHash(txhash common.Hash, val interface{})
log.Error("DeleteItemByTxHash: failed to delete trade", "txhash", txhash, "err", err)
}
case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
switch item.Type {
case lendingstate.Repay:
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()
query := bson.M{"txHash": txhash.Hex()}
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
result := []*tradingstate.OrderItem{}
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
case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
result := []*lendingstate.LendingItem{}
switch item.Type {
case lendingstate.Repay:
@ -529,7 +519,7 @@ func (db *MongoDatabase) GetListItemByHashes(hashes []string, val interface{}) i
query := bson.M{"hash": bson.M{"$in": hashes}}
switch val.(type) {
switch item := val.(type) {
case *tradingstate.OrderItem:
result := []*tradingstate.OrderItem{}
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
case *lendingstate.LendingItem:
item := val.(*lendingstate.LendingItem)
result := []*lendingstate.LendingItem{}
switch item.Type {
case lendingstate.Repay:
@ -835,7 +824,10 @@ func (db *MongoDatabase) EnsureIndexes() 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.

View file

@ -13,6 +13,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCxDAO"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/common/prque"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/state"
@ -20,7 +21,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/p2p"
"github.com/XinFinOrg/XDPoSChain/rpc"
lru "github.com/hashicorp/golang-lru"
)
const (
@ -42,8 +42,8 @@ type Lending struct {
orderNonce map[common.Address]*big.Int
XDCx *XDCx.XDCX
lendingItemHistory *lru.Cache
lendingTradeHistory *lru.Cache
lendingItemHistory *lru.Cache[common.Hash, map[common.Hash]lendingstate.LendingItemHistoryItem]
lendingTradeHistory *lru.Cache[common.Hash, map[common.Hash]lendingstate.LendingTradeHistoryItem]
}
func (l *Lending) Protocols() []p2p.Protocol {
@ -62,13 +62,11 @@ func (l *Lending) Stop() error {
}
func New(XDCx *XDCx.XDCX) *Lending {
itemCache, _ := lru.New(defaultCacheLimit)
lendingTradeCache, _ := lru.New(defaultCacheLimit)
lending := &Lending{
orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil),
lendingItemHistory: itemCache,
lendingTradeHistory: lendingTradeCache,
lendingItemHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingItemHistoryItem](defaultCacheLimit),
lendingTradeHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingTradeHistoryItem](defaultCacheLimit),
}
lending.StateCache = lendingstate.NewDatabase(XDCx.GetLevelDB())
lending.XDCx = XDCx
@ -311,7 +309,7 @@ func (l *Lending) SyncDataToSDKNode(chain consensus.ChainContext, statedb *state
}
// maker dirty order
makerFilledAmount := big.NewInt(0)
makerOrderHash := common.Hash{}
var makerOrderHash common.Hash
if updatedTakerLendingItem.Side == lendingstate.Borrowing {
makerOrderHash = tradeRecord.InvestingOrderHash
} else {
@ -665,7 +663,7 @@ func (l *Lending) GetLendingState(block *types.Block, author common.Address) (*l
return nil, err
}
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)
if err != nil {
@ -684,10 +682,7 @@ func (l *Lending) HasLendingState(block *types.Block, author common.Address) boo
return false
}
_, err = l.StateCache.OpenTrie(root)
if err != nil {
return false
}
return true
return err == nil
}
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) {
var lendingCacheAtTxHash map[common.Hash]lendingstate.LendingItemHistoryItem
c, ok := l.lendingItemHistory.Get(txhash)
if !ok || c == nil {
lendingCacheAtTxHash, ok := l.lendingItemHistory.Get(txhash)
if !ok || lendingCacheAtTxHash == nil {
lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingItemHistoryItem)
} else {
lendingCacheAtTxHash = c.(map[common.Hash]lendingstate.LendingItemHistoryItem)
}
orderKey := lendingstate.GetLendingItemHistoryKey(LendingToken, CollateralToken, hash)
_, 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) {
var lendingCacheAtTxHash map[common.Hash]lendingstate.LendingTradeHistoryItem
c, ok := l.lendingTradeHistory.Get(txhash)
if !ok || c == nil {
lendingCacheAtTxHash, ok := l.lendingTradeHistory.Get(txhash)
if !ok || lendingCacheAtTxHash == nil {
lendingCacheAtTxHash = make(map[common.Hash]lendingstate.LendingTradeHistoryItem)
} else {
lendingCacheAtTxHash = c.(map[common.Hash]lendingstate.LendingTradeHistoryItem)
}
_, ok = lendingCacheAtTxHash[hash]
if !ok {
@ -746,16 +736,15 @@ func (l *Lending) RollbackLendingData(txhash common.Hash) error {
items := db.GetListItemByTxHash(txhash, &lendingstate.LendingItem{})
if items != nil {
for _, item := range items.([]*lendingstate.LendingItem) {
c, ok := l.lendingItemHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback lendingItem", "txhash", txhash.Hex(), "item", lendingstate.ToJSON(item), "lendingItemHistory", c)
if !ok {
cacheAtTxHash, ok := l.lendingItemHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback lendingItem", "txhash", txhash.Hex(), "item", lendingstate.ToJSON(item), "lendingItemHistory", cacheAtTxHash)
if !ok || cacheAtTxHash == nil {
log.Debug("XDCxlending reorg: remove item due to no lendingItemHistory", "item", lendingstate.ToJSON(item))
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))
}
continue
}
cacheAtTxHash := c.(map[common.Hash]lendingstate.LendingItemHistoryItem)
lendingItemHistory := cacheAtTxHash[lendingstate.GetLendingItemHistoryKey(item.LendingToken, item.CollateralToken, item.Hash)]
if (lendingItemHistory == lendingstate.LendingItemHistoryItem{}) {
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{})
if items != nil {
for _, trade := range items.([]*lendingstate.LendingTrade) {
c, ok := l.lendingTradeHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback LendingTrade", "txhash", txhash.Hex(), "trade", lendingstate.ToJSON(trade), "LendingTradeHistory", c)
if !ok {
cacheAtTxHash, ok := l.lendingTradeHistory.Get(txhash)
log.Debug("XDCxlending reorg: rollback LendingTrade", "txhash", txhash.Hex(), "trade", lendingstate.ToJSON(trade), "LendingTradeHistory", cacheAtTxHash)
if !ok || cacheAtTxHash == nil {
log.Debug("XDCxlending reorg: remove trade due to no LendingTradeHistory", "trade", lendingstate.ToJSON(trade))
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))
}
continue
}
cacheAtTxHash := c.(map[common.Hash]lendingstate.LendingTradeHistoryItem)
lendingTradeHistoryItem := cacheAtTxHash[trade.Hash]
if (lendingTradeHistoryItem == lendingstate.LendingTradeHistoryItem{}) {
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)
log.Debug("TestRecall", "borrower", trade.Borrower.Hex(), "lendingToken", trade.LendingToken.Hex(), "collateral", trade.CollateralToken.Hex(), "price", price, "tradingIdHash", tradingIdHash.Hex())
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 {
log.Error("ProcessRecallLendingTrade", "lendingBook", lendingBook.Hex(), "tradingIdHash", tradingIdHash.Hex(), "newLiquidatePrice", newLiquidatePrice, "err", err)
return updatedTrades, liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades, err

View file

@ -23,7 +23,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/trie"
lru "github.com/hashicorp/golang-lru"
)
// 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
// reasonable chain reorg depths will hit an existing trie.
maxPastTries = 12
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
)
// 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
// high level trie abstraction.
func NewDatabase(db ethdb.Database) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{
db: trie.NewDatabase(db),
codeSizeCache: csc,
db: trie.NewDatabase(db),
// codeSizeCache: csc,
}
}
type cachingDB struct {
db *trie.Database
mu sync.Mutex
pastTries []*XDCXTrie
codeSizeCache *lru.Cache
db *trie.Database
mu sync.Mutex
pastTries []*XDCXTrie
}
// OpenTrie opens the main account trie.

View file

@ -18,11 +18,11 @@ package lendingstate
import (
"fmt"
"github.com/XinFinOrg/XDPoSChain/rlp"
"math/big"
"sort"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie"
)
@ -39,13 +39,13 @@ type DumpOrderBookInfo struct {
LowestLiquidationTime *big.Int
}
func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getInvestingTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
@ -57,15 +57,15 @@ func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.I
} else {
var data itemList
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)
mapResult[interest] = stateOrderList.DumpItemList(self.db)
mapResult[interest] = stateOrderList.DumpItemList(ls.db)
}
}
for interestHash, itemList := range exhangeObject.investingStates {
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{}
@ -82,13 +82,13 @@ func (self *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.I
return result, nil
}
func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.Int]DumpOrderList, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getBorrowingTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
@ -100,15 +100,15 @@ func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.I
} else {
var data itemList
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)
mapResult[interest] = stateOrderList.DumpItemList(self.db)
mapResult[interest] = stateOrderList.DumpItemList(ls.db)
}
}
for interestHash, itemList := range exhangeObject.borrowingStates {
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{}
@ -125,13 +125,13 @@ func (self *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.I
return result, nil
}
func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getInvestingTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
@ -143,7 +143,7 @@ func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*
} else {
var data itemList
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)
mapResult[interest] = stateOrderList.data.Volume
@ -168,13 +168,13 @@ func (self *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*
return result, nil
}
func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*big.Int, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getBorrowingTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
@ -186,7 +186,7 @@ func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*
} else {
var data itemList
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)
mapResult[interest] = stateOrderList.data.Volume
@ -211,22 +211,22 @@ func (self *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*
return result, nil
}
func (self *itemListState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil))
func (il *itemListState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: il.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(il.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
continue
}
if _, exist := self.cachedStorage[keyHash]; exist {
if _, exist := il.cachedStorage[keyHash]; exist {
continue
} else {
_, content, _, _ := rlp.Split(orderListIt.Value)
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) {
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 {
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 {
result.Orders[id] = mapResult.Orders[id]
}
return result
}
func (self *LendingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) DumpOrderBookInfo(orderBook common.Hash) (*DumpOrderBookInfo, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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.Nonce = exhangeObject.data.Nonce
result.TradeNonce = exhangeObject.data.TradeNonce
result.BestInvesting = new(big.Int).SetBytes(exhangeObject.getBestInvestingInterest(self.db).Bytes())
result.BestBorrowing = new(big.Int).SetBytes(exhangeObject.getBestBorrowingInterest(self.db).Bytes())
lowestLiquidationTime, _ := exhangeObject.getLowestLiquidationTime(self.db)
result.BestInvesting = new(big.Int).SetBytes(exhangeObject.getBestInvestingInterest(ls.db).Bytes())
result.BestBorrowing = new(big.Int).SetBytes(exhangeObject.getBestBorrowingInterest(ls.db).Bytes())
lowestLiquidationTime, _ := exhangeObject.getLowestLiquidationTime(ls.db)
result.LowestLiquidationTime = new(big.Int).SetBytes(lowestLiquidationTime.Bytes())
return result, nil
}
func (self *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: self.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(self.getTrie(db).NodeIterator(nil))
func (lts *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
mapResult := DumpOrderList{Volume: lts.Volume(), Orders: map[*big.Int]*big.Int{}}
orderListIt := trie.NewIterator(lts.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
continue
}
if _, exist := self.cachedStorage[keyHash]; exist {
if _, exist := lts.cachedStorage[keyHash]; exist {
continue
} else {
_, content, _, _ := rlp.Split(orderListIt.Value)
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) {
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 {
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 {
result.Orders[id] = mapResult.Orders[id]
}
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 {
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{}
it := trie.NewIterator(exhangeObject.getLiquidationTimeTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getLiquidationTimeTrie(ls.db).NodeIterator(nil))
for it.Next() {
unixTimeHash := common.BytesToHash(it.Key)
if common.EmptyHash(unixTimeHash) {
@ -311,15 +312,15 @@ func (self *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[
} else {
var data itemList
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)
mapResult[unixTime] = stateOrderList.DumpItemList(self.db)
mapResult[unixTime] = stateOrderList.DumpItemList(ls.db)
}
}
for unixTimeHash, itemList := range exhangeObject.liquidationTimeStates {
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{}
@ -336,13 +337,13 @@ func (self *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[
return result, nil
}
func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*big.Int]LendingItem, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*big.Int]LendingItem, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getLendingItemTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getLendingItemTrie(ls.db).NodeIterator(nil))
for it.Next() {
orderIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(orderIdHash) {
@ -354,7 +355,7 @@ func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*bi
} else {
var data LendingItem
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
}
@ -376,13 +377,13 @@ func (self *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*bi
return result, nil
}
func (self *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*big.Int]LendingTrade, error) {
exhangeObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*big.Int]LendingTrade, error) {
exhangeObject := ls.getLendingExchange(orderBook)
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{}
it := trie.NewIterator(exhangeObject.getLendingTradeTrie(self.db).NodeIterator(nil))
it := trie.NewIterator(exhangeObject.getLendingTradeTrie(ls.db).NodeIterator(nil))
for it.Next() {
tradeIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(tradeIdHash) {
@ -394,7 +395,7 @@ func (self *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*bi
} else {
var data LendingTrade
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
}

View file

@ -10,8 +10,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/globalsign/mgo/bson"
"golang.org/x/crypto/sha3"
)
const (
@ -207,7 +207,7 @@ func (l *LendingItem) VerifyLendingItem(state *state.StateDB) error {
if err := l.VerifyLendingStatus(); err != nil {
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)
}
if l.Status == LendingStatusNew {
@ -308,7 +308,7 @@ func (l *LendingItem) VerifyLendingStatus() error {
}
func (l *LendingItem) ComputeHash() common.Hash {
sha := sha3.NewKeccak256()
sha := sha3.NewLegacyKeccak256()
if l.Status == LendingStatusNew {
sha.Write(l.Relayer.Bytes())
sha.Write(l.UserAddress.Bytes())
@ -411,7 +411,7 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
if lendTokenXDCPrice != nil && lendTokenXDCPrice.Sign() > 0 {
defaultFee := new(big.Int).Mul(quantity, new(big.Int).SetUint64(DefaultFeeRate))
defaultFee = new(big.Int).Div(defaultFee, common.XDCXBaseFee)
defaultFeeInXDC := common.Big0
var defaultFeeInXDC *big.Int
if lendingToken != common.XDCNativeAddressBinary {
defaultFeeInXDC = new(big.Int).Mul(defaultFee, lendTokenXDCPrice)
defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, lendingTokenDecimal)
@ -429,8 +429,7 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
// make sure actualBalance >= cancel fee
lendingBook := GetLendingOrderBookHash(lendingToken, term)
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)
actualBalance := GetTokenBalance(userAddress, lendingToken, statedb)
@ -459,9 +458,8 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
case LendingStatusCancelled:
lendingBook := GetLendingOrderBookHash(lendingToken, term)
item := lendingStateDb.GetLendingOrder(lendingBook, common.BigToHash(new(big.Int).SetUint64(lendingId)))
cancelFee := big.NewInt(0)
// 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).Div(cancelFee, common.XDCXBaseCancelFee)
actualBalance := GetTokenBalance(userAddress, collateralToken, statedb)

View file

@ -12,8 +12,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/rpc"
"golang.org/x/crypto/sha3"
)
func TestLendingItem_VerifyLendingSide(t *testing.T) {
@ -515,11 +515,11 @@ func Test_CreateOrder(t *testing.T) {
func sendOrder(nonce uint64) {
rpcClient, err := rpc.DialHTTP("http://localhost:8501")
defer rpcClient.Close()
if err != nil {
fmt.Println("rpc.DialHTTP failed", "err", err)
os.Exit(1)
}
defer rpcClient.Close()
rand.Seed(time.Now().UTC().UnixNano())
item := &LendingOrderMsg{
AccountNonce: nonce,
@ -568,9 +568,8 @@ func sendOrder(nonce uint64) {
}
func computeHash(l *LendingOrderMsg) common.Hash {
sha := sha3.NewKeccak256()
sha := sha3.NewLegacyKeccak256()
if l.Status == LendingStatusCancelled {
sha := sha3.NewKeccak256()
sha.Write(l.Hash.Bytes())
sha.Write(common.BigToHash(big.NewInt(int64(l.AccountNonce))).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())
}
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"]
locBig := GetLocMappingAtKey(relayer.Hash(), slot)
locHash := common.BigToHash(locBig)
if statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), locHash) != (common.Hash{}) {
return true
}
return false
return statedb.GetState(common.HexToAddress(common.RelayerRegistrationSMC), locHash) != (common.Hash{})
}
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)
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 {
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 {
return newBalance, nil
}

View file

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

View file

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

View file

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

View file

@ -19,11 +19,12 @@ package lendingstate
import (
"bytes"
"fmt"
"io"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie"
"io"
"math/big"
)
type liquidationTimeState struct {
@ -47,8 +48,8 @@ type liquidationTimeState struct {
onDirty func(time common.Hash) // Callback method to mark a state object newly dirty
}
func (s *liquidationTimeState) empty() bool {
return s.data.Volume == nil || s.data.Volume.Sign() == 0
func (lt *liquidationTimeState) empty() bool {
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 {
@ -62,59 +63,59 @@ func newLiquidationTimeState(time common.Hash, lendingBook common.Hash, data ite
}
}
func (self *liquidationTimeState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, self.data)
func (lt *liquidationTimeState) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, lt.data)
}
func (self *liquidationTimeState) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
func (lt *liquidationTimeState) setError(err error) {
if lt.dbErr == nil {
lt.dbErr = err
}
}
func (self *liquidationTimeState) getTrie(db Database) Trie {
if self.trie == nil {
func (lt *liquidationTimeState) getTrie(db Database) Trie {
if lt.trie == nil {
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 {
self.trie, _ = db.OpenStorageTrie(self.time, EmptyHash)
self.setError(fmt.Errorf("can't create storage trie: %v", err))
lt.trie, _ = db.OpenStorageTrie(lt.time, EmptyHash)
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 {
amount, exists := self.cachedStorage[tradeId]
func (lt *liquidationTimeState) Exist(db Database, tradeId common.Hash) bool {
amount, exists := lt.cachedStorage[tradeId]
if exists {
return true
}
// 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 {
self.setError(err)
lt.setError(err)
return false
}
if len(enc) > 0 {
_, content, _, err := rlp.Split(enc)
if err != nil {
self.setError(err)
lt.setError(err)
}
amount.SetBytes(content)
}
if (amount != common.Hash{}) {
self.cachedStorage[tradeId] = amount
lt.cachedStorage[tradeId] = amount
}
return true
}
func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
func (lt *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
tradeIds := []common.Hash{}
lendingBookTrie := self.getTrie(db)
lendingBookTrie := lt.getTrie(db)
if lendingBookTrie == nil {
return tradeIds
}
for id, value := range self.cachedStorage {
for id, value := range lt.cachedStorage {
if !common.EmptyHash(value) {
tradeIds = append(tradeIds, id)
}
@ -122,7 +123,7 @@ func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
orderListIt := trie.NewIterator(lendingBookTrie.NodeIterator(nil))
for orderListIt.Next() {
id := common.BytesToHash(orderListIt.Key)
if _, exist := self.cachedStorage[id]; exist {
if _, exist := lt.cachedStorage[id]; exist {
continue
}
tradeIds = append(tradeIds, id)
@ -130,83 +131,83 @@ func (self *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
return tradeIds
}
func (self *liquidationTimeState) insertTradeId(db Database, tradeId common.Hash) {
self.setTradeId(tradeId, tradeId)
self.setError(self.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
func (lt *liquidationTimeState) insertTradeId(db Database, tradeId common.Hash) {
lt.setTradeId(tradeId, tradeId)
lt.setError(lt.getTrie(db).TryUpdate(tradeId[:], tradeId[:]))
}
func (self *liquidationTimeState) removeTradeId(db Database, tradeId common.Hash) {
tr := self.getTrie(db)
self.setError(tr.TryDelete(tradeId[:]))
self.setTradeId(tradeId, EmptyHash)
func (lt *liquidationTimeState) removeTradeId(db Database, tradeId common.Hash) {
tr := lt.getTrie(db)
lt.setError(tr.TryDelete(tradeId[:]))
lt.setTradeId(tradeId, EmptyHash)
}
func (self *liquidationTimeState) setTradeId(tradeId common.Hash, value common.Hash) {
self.cachedStorage[tradeId] = value
self.dirtyStorage[tradeId] = value
func (lt *liquidationTimeState) setTradeId(tradeId common.Hash, value common.Hash) {
lt.cachedStorage[tradeId] = value
lt.dirtyStorage[tradeId] = value
if self.onDirty != nil {
self.onDirty(self.lendingBook)
self.onDirty = nil
if lt.onDirty != nil {
lt.onDirty(lt.lendingBook)
lt.onDirty = nil
}
}
func (self *liquidationTimeState) updateTrie(db Database) Trie {
tr := self.getTrie(db)
for key, value := range self.dirtyStorage {
delete(self.dirtyStorage, key)
func (lt *liquidationTimeState) updateTrie(db Database) Trie {
tr := lt.getTrie(db)
for key, value := range lt.dirtyStorage {
delete(lt.dirtyStorage, key)
if value == EmptyHash {
self.setError(tr.TryDelete(key[:]))
lt.setError(tr.TryDelete(key[:]))
continue
}
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
self.setError(tr.TryUpdate(key[:], v))
lt.setError(tr.TryUpdate(key[:], v))
}
return tr
}
func (self *liquidationTimeState) updateRoot(db Database) error {
self.updateTrie(db)
if self.dbErr != nil {
return self.dbErr
func (lt *liquidationTimeState) updateRoot(db Database) error {
lt.updateTrie(db)
if lt.dbErr != nil {
return lt.dbErr
}
root, err := self.trie.Commit(nil)
root, err := lt.trie.Commit(nil)
if err == nil {
self.data.Root = root
lt.data.Root = root
}
return err
}
func (self *liquidationTimeState) deepCopy(db *LendingStateDB, onDirty func(time common.Hash)) *liquidationTimeState {
stateLendingBook := newLiquidationTimeState(self.lendingBook, self.time, self.data, onDirty)
if self.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(self.trie)
func (lt *liquidationTimeState) deepCopy(db *LendingStateDB, onDirty func(time common.Hash)) *liquidationTimeState {
stateLendingBook := newLiquidationTimeState(lt.lendingBook, lt.time, lt.data, onDirty)
if lt.trie != nil {
stateLendingBook.trie = db.db.CopyTrie(lt.trie)
}
for key, value := range self.dirtyStorage {
for key, value := range lt.dirtyStorage {
stateLendingBook.dirtyStorage[key] = value
}
for key, value := range self.cachedStorage {
for key, value := range lt.cachedStorage {
stateLendingBook.cachedStorage[key] = value
}
return stateLendingBook
}
func (c *liquidationTimeState) AddVolume(amount *big.Int) {
c.setVolume(new(big.Int).Add(c.data.Volume, amount))
func (lt *liquidationTimeState) AddVolume(amount *big.Int) {
lt.setVolume(new(big.Int).Add(lt.data.Volume, amount))
}
func (c *liquidationTimeState) subVolume(amount *big.Int) {
c.setVolume(new(big.Int).Sub(c.data.Volume, amount))
func (lt *liquidationTimeState) subVolume(amount *big.Int) {
lt.setVolume(new(big.Int).Sub(lt.data.Volume, amount))
}
func (self *liquidationTimeState) setVolume(volume *big.Int) {
self.data.Volume = volume
if self.onDirty != nil {
self.onDirty(self.lendingBook)
self.onDirty = nil
func (lt *liquidationTimeState) setVolume(volume *big.Int) {
lt.data.Volume = volume
if lt.onDirty != nil {
lt.onDirty(lt.lendingBook)
lt.onDirty = nil
}
}
func (self *liquidationTimeState) Volume() *big.Int {
return self.data.Volume
func (lt *liquidationTimeState) Volume() *big.Int {
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.
func (self *LendingStateDB) setError(err error) {
if self.dbErr == nil {
self.dbErr = err
func (ls *LendingStateDB) setError(err error) {
if ls.dbErr == nil {
ls.dbErr = err
}
}
func (self *LendingStateDB) Error() error {
return self.dbErr
func (ls *LendingStateDB) Error() error {
return ls.dbErr
}
// Exist reports whether the given tradeId address exists in the state.
// Notably this also returns true for suicided lenddinges.
func (self *LendingStateDB) Exist(addr common.Hash) bool {
return self.getLendingExchange(addr) != nil
func (ls *LendingStateDB) Exist(addr common.Hash) bool {
return ls.getLendingExchange(addr) != nil
}
// Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *LendingStateDB) Empty(addr common.Hash) bool {
so := self.getLendingExchange(addr)
func (ls *LendingStateDB) Empty(addr common.Hash) bool {
so := ls.getLendingExchange(addr)
return so == nil || so.empty()
}
func (self *LendingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := self.getLendingExchange(addr)
func (ls *LendingStateDB) GetNonce(addr common.Hash) uint64 {
stateObject := ls.getLendingExchange(addr)
if stateObject != nil {
return stateObject.Nonce()
}
return 0
}
func (self *LendingStateDB) GetTradeNonce(addr common.Hash) uint64 {
stateObject := self.getLendingExchange(addr)
func (ls *LendingStateDB) GetTradeNonce(addr common.Hash) uint64 {
stateObject := ls.getLendingExchange(addr)
if stateObject != nil {
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.
func (self *LendingStateDB) Database() Database {
return self.db
func (ls *LendingStateDB) Database() Database {
return ls.db
}
func (self *LendingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := self.GetOrNewLendingExchangeObject(addr)
func (ls *LendingStateDB) SetNonce(addr common.Hash, nonce uint64) {
stateObject := ls.GetOrNewLendingExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, nonceChange{
ls.journal = append(ls.journal, nonceChange{
hash: addr,
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) {
stateObject := self.GetOrNewLendingExchangeObject(addr)
func (ls *LendingStateDB) SetTradeNonce(addr common.Hash, nonce uint64) {
stateObject := ls.GetOrNewLendingExchangeObject(addr)
if stateObject != nil {
self.journal = append(self.journal, tradeNonceChange{
ls.journal = append(ls.journal, tradeNonceChange{
hash: addr,
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)
stateExchange := self.getLendingExchange(orderBook)
stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook)
stateExchange = ls.createLendingExchangeObject(orderBook)
}
var stateOrderList *itemListState
switch order.Side {
case Investing:
stateOrderList = stateExchange.getInvestingOrderList(self.db, interestHash)
stateOrderList = stateExchange.getInvestingOrderList(ls.db, interestHash)
if stateOrderList == nil {
stateOrderList = stateExchange.createInvestingOrderList(self.db, interestHash)
stateOrderList = stateExchange.createInvestingOrderList(ls.db, interestHash)
}
case Borrowing:
stateOrderList = stateExchange.getBorrowingOrderList(self.db, interestHash)
stateOrderList = stateExchange.getBorrowingOrderList(ls.db, interestHash)
if stateOrderList == nil {
stateOrderList = stateExchange.createBorrowingOrderList(self.db, interestHash)
stateOrderList = stateExchange.createBorrowingOrderList(ls.db, interestHash)
}
default:
return
}
self.journal = append(self.journal, insertOrder{
ls.journal = append(ls.journal, insertOrder{
orderBook: orderBook,
orderId: orderId,
order: &order,
})
stateExchange.createLendingItem(self.db, orderId, order)
stateOrderList.insertLendingItem(self.db, orderId, common.BigToHash(order.Quantity))
stateExchange.createLendingItem(ls.db, orderId, order)
stateOrderList.insertLendingItem(ls.db, orderId, common.BigToHash(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)
stateExchange := self.getLendingExchange(orderBook)
stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook)
stateExchange = ls.createLendingExchangeObject(orderBook)
}
prvTrade := self.GetLendingTrade(orderBook, tradeIdHash)
self.journal = append(self.journal, insertTrading{
prvTrade := ls.GetLendingTrade(orderBook, tradeIdHash)
ls.journal = append(ls.journal, insertTrading{
orderBook: orderBook,
tradeId: tradeId,
prvTrade: &prvTrade,
@ -185,88 +185,90 @@ func (self *LendingStateDB) InsertTradingItem(orderBook common.Hash, tradeId uin
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)
stateExchange := self.getLendingExchange(orderBook)
stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook)
stateExchange = ls.createLendingExchangeObject(orderBook)
}
stateLendingTrade := stateExchange.getLendingTrade(self.db, tradeIdHash)
self.journal = append(self.journal, liquidationPriceChange{
stateLendingTrade := stateExchange.getLendingTrade(ls.db, tradeIdHash)
ls.journal = append(ls.journal, liquidationPriceChange{
orderBook: orderBook,
tradeId: tradeIdHash,
prev: stateLendingTrade.data.LiquidationPrice,
})
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)
stateExchange := self.getLendingExchange(orderBook)
stateExchange := ls.getLendingExchange(orderBook)
if stateExchange == nil {
stateExchange = self.createLendingExchangeObject(orderBook)
stateExchange = ls.createLendingExchangeObject(orderBook)
}
stateLendingTrade := stateExchange.getLendingTrade(self.db, tradeIdHash)
self.journal = append(self.journal, collateralLockedAmount{
stateLendingTrade := stateExchange.getLendingTrade(ls.db, tradeIdHash)
ls.journal = append(ls.journal, collateralLockedAmount{
orderBook: orderBook,
tradeId: tradeIdHash,
prev: stateLendingTrade.data.CollateralLockedAmount,
})
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 {
return EmptyLendingOrder
}
stateOrderItem := stateObject.getLendingItem(self.db, orderId)
stateOrderItem := stateObject.getLendingItem(ls.db, orderId)
if stateOrderItem == nil {
return EmptyLendingOrder
}
return stateOrderItem.data
}
func (self *LendingStateDB) GetLendingTrade(orderBook common.Hash, tradeId common.Hash) LendingTrade {
stateObject := self.GetOrNewLendingExchangeObject(orderBook)
func (ls *LendingStateDB) GetLendingTrade(orderBook common.Hash, tradeId common.Hash) LendingTrade {
stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject == nil {
return EmptyLendingTrade
}
stateOrderItem := stateObject.getLendingTrade(self.db, tradeId)
stateOrderItem := stateObject.getLendingTrade(ls.db, tradeId)
if stateOrderItem == nil || stateOrderItem.empty() {
return EmptyLendingTrade
}
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)
lendingExchange := self.GetOrNewLendingExchangeObject(orderBook)
lendingExchange := ls.GetOrNewLendingExchangeObject(orderBook)
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
switch side {
case Investing:
orderList = lendingExchange.getInvestingOrderList(self.db, priceHash)
orderList = lendingExchange.getInvestingOrderList(ls.db, priceHash)
case Borrowing:
orderList = lendingExchange.getBorrowingOrderList(self.db, priceHash)
orderList = lendingExchange.getBorrowingOrderList(ls.db, priceHash)
default:
return fmt.Errorf("Order type not found : %s ", side)
return fmt.Errorf("not found order type: %s", side)
}
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() {
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 {
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,
orderId: orderId,
order: self.GetLendingOrder(orderBook, orderId),
order: ls.GetLendingOrder(orderBook, orderId),
amount: 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())
orderList.subVolume(amount)
if newAmount.Sign() == 0 {
orderList.removeOrderItem(self.db, orderId)
orderList.removeOrderItem(ls.db, orderId)
} else {
orderList.setOrderItem(orderId, common.BigToHash(newAmount))
}
if orderList.empty() {
switch side {
case Investing:
lendingExchange.removeInvestingOrderList(self.db, orderList)
lendingExchange.removeInvestingOrderList(ls.db, orderList)
case Borrowing:
lendingExchange.removeBorrowingOrderList(self.db, orderList)
lendingExchange.removeBorrowingOrderList(ls.db, orderList)
default:
}
}
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)
orderIdHash := common.BigToHash(new(big.Int).SetUint64(order.LendingId))
stateObject := self.GetOrNewLendingExchangeObject(orderBook)
stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
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
switch lendingItem.data.Side {
case Investing:
orderList = stateObject.getInvestingOrderList(self.db, interestHash)
orderList = stateObject.getInvestingOrderList(ls.db, interestHash)
case Borrowing:
orderList = stateObject.getBorrowingOrderList(self.db, interestHash)
orderList = stateObject.getBorrowingOrderList(ls.db, interestHash)
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() {
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() {
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 {
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,
orderId: orderIdHash,
order: self.GetLendingOrder(orderBook, orderIdHash),
order: ls.GetLendingOrder(orderBook, orderIdHash),
})
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.removeOrderItem(self.db, orderIdHash)
orderList.removeOrderItem(ls.db, orderIdHash)
if orderList.empty() {
switch order.Side {
case Investing:
stateObject.removeInvestingOrderList(self.db, orderList)
stateObject.removeInvestingOrderList(ls.db, orderList)
case Borrowing:
stateObject.removeBorrowingOrderList(self.db, orderList)
stateObject.removeBorrowingOrderList(ls.db, orderList)
default:
}
}
return nil
}
func (self *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil {
investingHash := stateObject.getBestInvestingInterest(self.db)
investingHash := stateObject.getBestInvestingInterest(ls.db)
if common.EmptyHash(investingHash) {
return Zero, Zero
}
orderList := stateObject.getInvestingOrderList(self.db, investingHash)
orderList := stateObject.getInvestingOrderList(ls.db, investingHash)
if orderList == nil {
log.Error("order list investing not found", "key", investingHash.Hex())
return Zero, Zero
@ -354,14 +356,14 @@ func (self *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.In
return Zero, Zero
}
func (self *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := self.getLendingExchange(orderBook)
func (ls *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int, *big.Int) {
stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil {
priceHash := stateObject.getBestBorrowingInterest(self.db)
priceHash := stateObject.getBestBorrowingInterest(ls.db)
if common.EmptyHash(priceHash) {
return Zero, Zero
}
orderList := stateObject.getBorrowingOrderList(self.db, priceHash)
orderList := stateObject.getBorrowingOrderList(ls.db, priceHash)
if orderList == nil {
log.Error("order list ask not found", "key", priceHash.Hex())
return Zero, Zero
@ -371,52 +373,52 @@ func (self *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int,
return Zero, Zero
}
func (self *LendingStateDB) GetBestLendingIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := self.GetOrNewLendingExchangeObject(orderBook)
func (ls *LendingStateDB) GetBestLendingIdAndAmount(orderBook common.Hash, price *big.Int, side string) (common.Hash, *big.Int, error) {
stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
if stateObject != nil {
var stateOrderList *itemListState
switch side {
case Investing:
stateOrderList = stateObject.getInvestingOrderList(self.db, common.BigToHash(price))
stateOrderList = stateObject.getInvestingOrderList(ls.db, common.BigToHash(price))
case Borrowing:
stateOrderList = stateObject.getBorrowingOrderList(self.db, common.BigToHash(price))
stateOrderList = stateObject.getBorrowingOrderList(ls.db, common.BigToHash(price))
default:
return EmptyHash, Zero, fmt.Errorf("not found side :%s ", side)
return EmptyHash, Zero, fmt.Errorf("not found side: %s", side)
}
if stateOrderList != nil {
key, _, err := stateOrderList.getTrie(self.db).TryGetBestLeftKeyAndValue()
key, _, err := stateOrderList.getTrie(ls.db).TryGetBestLeftKeyAndValue()
if err != nil {
return EmptyHash, Zero, err
}
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 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.
func (self *LendingStateDB) updateLendingExchange(stateObject *lendingExchangeState) {
func (ls *LendingStateDB) updateLendingExchange(stateObject *lendingExchangeState) {
addr := stateObject.Hash()
data, err := rlp.EncodeToBytes(stateObject)
if err != nil {
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.
func (self *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *lendingExchangeState) {
func (ls *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *lendingExchangeState) {
// Prefer 'live' objects.
if obj := self.lendingExchangeStates[addr]; obj != nil {
if obj := ls.lendingExchangeStates[addr]; obj != nil {
return obj
}
// Load the object from the database.
enc, err := self.trie.TryGet(addr[:])
enc, err := ls.trie.TryGet(addr[:])
if len(enc) == 0 {
self.setError(err)
ls.setError(err)
return nil
}
var data lendingObject
@ -425,176 +427,176 @@ func (self *LendingStateDB) getLendingExchange(addr common.Hash) (stateObject *l
return nil
}
// Insert into the live set.
obj := newStateExchanges(self, addr, data, self.MarkLendingExchangeObjectDirty)
self.lendingExchangeStates[addr] = obj
obj := newStateExchanges(ls, addr, data, ls.MarkLendingExchangeObjectDirty)
ls.lendingExchangeStates[addr] = obj
return obj
}
func (self *LendingStateDB) setLendingExchangeObject(object *lendingExchangeState) {
self.lendingExchangeStates[object.Hash()] = object
self.lendingExchangeStatesDirty[object.Hash()] = struct{}{}
func (ls *LendingStateDB) setLendingExchangeObject(object *lendingExchangeState) {
ls.lendingExchangeStates[object.Hash()] = object
ls.lendingExchangeStatesDirty[object.Hash()] = struct{}{}
}
// Retrieve a state object or create a new state object if nil.
func (self *LendingStateDB) GetOrNewLendingExchangeObject(addr common.Hash) *lendingExchangeState {
stateExchangeObject := self.getLendingExchange(addr)
func (ls *LendingStateDB) GetOrNewLendingExchangeObject(addr common.Hash) *lendingExchangeState {
stateExchangeObject := ls.getLendingExchange(addr)
if stateExchangeObject == nil {
stateExchangeObject = self.createLendingExchangeObject(addr)
stateExchangeObject = ls.createLendingExchangeObject(addr)
}
return stateExchangeObject
}
// MarkStateLendObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
func (self *LendingStateDB) MarkLendingExchangeObjectDirty(addr common.Hash) {
self.lendingExchangeStatesDirty[addr] = struct{}{}
func (ls *LendingStateDB) MarkLendingExchangeObjectDirty(addr common.Hash) {
ls.lendingExchangeStatesDirty[addr] = struct{}{}
}
// 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.
func (self *LendingStateDB) createLendingExchangeObject(hash common.Hash) (newobj *lendingExchangeState) {
newobj = newStateExchanges(self, hash, lendingObject{}, self.MarkLendingExchangeObjectDirty)
func (ls *LendingStateDB) createLendingExchangeObject(hash common.Hash) (newobj *lendingExchangeState) {
newobj = newStateExchanges(ls, hash, lendingObject{}, ls.MarkLendingExchangeObjectDirty)
newobj.setNonce(0) // sets the object to dirty
self.setLendingExchangeObject(newobj)
ls.setLendingExchangeObject(newobj)
return newobj
}
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func (self *LendingStateDB) Copy() *LendingStateDB {
self.lock.Lock()
defer self.lock.Unlock()
func (ls *LendingStateDB) Copy() *LendingStateDB {
ls.lock.Lock()
defer ls.lock.Unlock()
// Copy all the basic fields, initialize the memory ones
state := &LendingStateDB{
db: self.db,
trie: self.db.CopyTrie(self.trie),
lendingExchangeStates: make(map[common.Hash]*lendingExchangeState, len(self.lendingExchangeStatesDirty)),
lendingExchangeStatesDirty: make(map[common.Hash]struct{}, len(self.lendingExchangeStatesDirty)),
db: ls.db,
trie: ls.db.CopyTrie(ls.trie),
lendingExchangeStates: make(map[common.Hash]*lendingExchangeState, len(ls.lendingExchangeStatesDirty)),
lendingExchangeStatesDirty: make(map[common.Hash]struct{}, len(ls.lendingExchangeStatesDirty)),
}
// Copy the dirty states, logs, and preimages
for addr := range self.lendingExchangeStatesDirty {
for addr := range ls.lendingExchangeStatesDirty {
state.lendingExchangeStatesDirty[addr] = struct{}{}
}
for addr, exchangeObject := range self.lendingExchangeStates {
for addr, exchangeObject := range ls.lendingExchangeStates {
state.lendingExchangeStates[addr] = exchangeObject.deepCopy(state, state.MarkLendingExchangeObjectDirty)
}
return state
}
func (s *LendingStateDB) clearJournalAndRefund() {
s.journal = nil
s.validRevisions = s.validRevisions[:0]
func (ls *LendingStateDB) clearJournalAndRefund() {
ls.journal = nil
ls.validRevisions = ls.validRevisions[:0]
}
// Snapshot returns an identifier for the current revision of the state.
func (self *LendingStateDB) Snapshot() int {
id := self.nextRevisionId
self.nextRevisionId++
self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)})
func (ls *LendingStateDB) Snapshot() int {
id := ls.nextRevisionId
ls.nextRevisionId++
ls.validRevisions = append(ls.validRevisions, revision{id, len(ls.journal)})
return id
}
// 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.
idx := sort.Search(len(self.validRevisions), func(i int) bool {
return self.validRevisions[i].id >= revid
idx := sort.Search(len(ls.validRevisions), func(i int) bool {
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))
}
snapshot := self.validRevisions[idx].journalIndex
snapshot := ls.validRevisions[idx].journalIndex
// Replay the journal to undo changes.
for i := len(self.journal) - 1; i >= snapshot; i-- {
self.journal[i].undo(self)
for i := len(ls.journal) - 1; i >= snapshot; i-- {
ls.journal[i].undo(ls)
}
self.journal = self.journal[:snapshot]
ls.journal = ls.journal[:snapshot]
// 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
// and clears the journal as well as the refunds.
func (s *LendingStateDB) Finalise() {
func (ls *LendingStateDB) Finalise() {
// Commit objects to the trie.
for addr, stateObject := range s.lendingExchangeStates {
if _, isDirty := s.lendingExchangeStatesDirty[addr]; isDirty {
for addr, stateObject := range ls.lendingExchangeStates {
if _, isDirty := ls.lendingExchangeStatesDirty[addr]; isDirty {
// 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 {
log.Warn("Finalise updateInvestingRoot", "err", err, "addr", addr, "stateObject", *stateObject)
}
stateObject.updateBorrowingRoot(s.db)
stateObject.updateOrderRoot(s.db)
stateObject.updateLendingTradeRoot(s.db)
stateObject.updateLiquidationTimeRoot(s.db)
stateObject.updateBorrowingRoot(ls.db)
stateObject.updateOrderRoot(ls.db)
stateObject.updateLendingTradeRoot(ls.db)
stateObject.updateLiquidationTimeRoot(ls.db)
// Update the object in the main tradeId trie.
s.updateLendingExchange(stateObject)
ls.updateLendingExchange(stateObject)
//delete(s.investingStatesDirty, addr)
}
}
s.clearJournalAndRefund()
ls.clearJournalAndRefund()
}
// IntermediateRoot computes the current root orderBook of the state trie.
// It is called in between transactions to get the root orderBook that
// goes into transaction receipts.
func (s *LendingStateDB) IntermediateRoot() common.Hash {
s.Finalise()
return s.trie.Hash()
func (ls *LendingStateDB) IntermediateRoot() common.Hash {
ls.Finalise()
return ls.trie.Hash()
}
// Commit writes the state to the underlying in-memory trie database.
func (s *LendingStateDB) Commit() (root common.Hash, err error) {
defer s.clearJournalAndRefund()
func (ls *LendingStateDB) Commit() (root common.Hash, err error) {
defer ls.clearJournalAndRefund()
// Commit objects to the trie.
for addr, stateObject := range s.lendingExchangeStates {
if _, isDirty := s.lendingExchangeStatesDirty[addr]; isDirty {
for addr, stateObject := range ls.lendingExchangeStates {
if _, isDirty := ls.lendingExchangeStatesDirty[addr]; isDirty {
// 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
}
if err := stateObject.CommitBorrowingTrie(s.db); err != nil {
if err := stateObject.CommitBorrowingTrie(ls.db); err != nil {
return EmptyHash, err
}
if err := stateObject.CommitLendingItemTrie(s.db); err != nil {
if err := stateObject.CommitLendingItemTrie(ls.db); err != nil {
return EmptyHash, err
}
if err := stateObject.CommitLendingTradeTrie(s.db); err != nil {
if err := stateObject.CommitLendingTradeTrie(ls.db); err != nil {
return EmptyHash, err
}
if err := stateObject.CommitLiquidationTimeTrie(s.db); err != nil {
if err := stateObject.CommitLiquidationTimeTrie(ls.db); err != nil {
return EmptyHash, err
}
// Update the object in the main tradeId trie.
s.updateLendingExchange(stateObject)
delete(s.lendingExchangeStatesDirty, addr)
ls.updateLendingExchange(stateObject)
delete(ls.lendingExchangeStatesDirty, addr)
}
}
// 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
if err := rlp.DecodeBytes(leaf, &exchange); err != nil {
return nil
}
if exchange.InvestingRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.InvestingRoot, parent)
ls.db.TrieDB().Reference(exchange.InvestingRoot, parent)
}
if exchange.BorrowingRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.BorrowingRoot, parent)
ls.db.TrieDB().Reference(exchange.BorrowingRoot, parent)
}
if exchange.LendingItemRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LendingItemRoot, parent)
ls.db.TrieDB().Reference(exchange.LendingItemRoot, parent)
}
if exchange.LendingTradeRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LendingTradeRoot, parent)
ls.db.TrieDB().Reference(exchange.LendingTradeRoot, parent)
}
if exchange.LiquidationTimeRoot != EmptyRoot {
s.db.TrieDB().Reference(exchange.LiquidationTimeRoot, parent)
ls.db.TrieDB().Reference(exchange.LiquidationTimeRoot, parent)
}
return nil
})
@ -602,38 +604,38 @@ func (s *LendingStateDB) Commit() (root common.Hash, err error) {
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)
lendingExchangeState := self.getLendingExchange(lendingBook)
lendingExchangeState := ls.getLendingExchange(lendingBook)
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 {
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)
}
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)
tradeIdHash := common.Uint64ToHash(tradeId)
lendingExchangeState := self.getLendingExchange(lendingBook)
lendingExchangeState := ls.getLendingExchange(lendingBook)
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 {
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) {
return fmt.Errorf("tradeId not exist : %s , %d , %d ", lendingBook.Hex(), time, tradeId)
if !liquidationTime.Exist(ls.db, tradeIdHash) {
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)
if liquidationTime.Volume().Sign() == 0 {
err := lendingExchangeState.getLiquidationTimeTrie(self.db).TryDelete(timeHash[:])
err := lendingExchangeState.getLiquidationTimeTrie(ls.db).TryDelete(timeHash[:])
if err != nil {
log.Warn("RemoveLiquidationTime getLiquidationTimeTrie.TryDelete", "err", err, "timeHash[:]", timeHash[:])
}
@ -641,33 +643,33 @@ func (self *LendingStateDB) RemoveLiquidationTime(lendingBook common.Hash, trade
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{}
lendingExchangeState := self.getLendingExchange(lendingBook)
lendingExchangeState := ls.getLendingExchange(lendingBook)
if lendingExchangeState == nil {
return common.Big0, liquidationData
}
lowestPriceHash, liquidationState := lendingExchangeState.getLowestLiquidationTime(self.db)
lowestPriceHash, liquidationState := lendingExchangeState.getLowestLiquidationTime(ls.db)
lowestTime := new(big.Int).SetBytes(lowestPriceHash[:])
if liquidationState != nil && lowestTime.Sign() > 0 && lowestTime.Cmp(time) <= 0 {
liquidationData = liquidationState.getAllTradeIds(self.db)
liquidationData = liquidationState.getAllTradeIds(ls.db)
}
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)
stateObject := self.GetOrNewLendingExchangeObject(orderBook)
stateObject := ls.GetOrNewLendingExchangeObject(orderBook)
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() {
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,
order: self.GetLendingTrade(orderBook, tradeIdHash),
order: ls.GetLendingTrade(orderBook, tradeIdHash),
})
lendingTrade.SetAmount(Zero)
return nil

View file

@ -18,10 +18,11 @@ package lendingstate
import (
"fmt"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
)
func TestEchangeStates(t *testing.T) {
@ -225,9 +226,7 @@ func TestDumpStates(t *testing.T) {
orderBook := common.StringToHash("BTC/XDC")
numberOrder := 20
orderItems := []LendingItem{}
relayers := []common.Hash{}
for i := 0; i < numberOrder; i++ {
relayers = append(relayers, common.BigToHash(big.NewInt(int64(i))))
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: Borrowing, Signature: &Signature{V: 1, R: common.HexToHash("3333333333"), S: common.HexToHash("22222222222222222")}})

View file

@ -2,14 +2,14 @@ package lendingstate
import (
"fmt"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"math/big"
"strconv"
"time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/globalsign/mgo/bson"
"golang.org/x/crypto/sha3"
)
const (
@ -183,7 +183,7 @@ func (t *LendingTrade) SetBSON(raw bson.Raw) error {
}
func (t *LendingTrade) ComputeHash() common.Hash {
sha := sha3.NewKeccak256()
sha := sha3.NewLegacyKeccak256()
sha.Write(t.InvestingOrderHash.Bytes())
sha.Write(t.BorrowingOrderHash.Bytes())
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 {
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 {
rejects = append(rejects, order)
}
@ -438,7 +438,7 @@ func (l *Lending) getLendQuantity(
}
LendingTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, makerOrder.LendingToken)
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
if takerOrder.Side == lendingstate.Borrowing {
@ -446,7 +446,7 @@ func (l *Lending) getLendQuantity(
}
collateralTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, collateralToken)
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 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)
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{}
//Checking balance
@ -727,9 +727,10 @@ func (l *Lending) ProcessCancelOrder(header *types.Header, lendingStateDB *lendi
}
}
feeRate := lendingstate.GetFee(statedb, originOrder.Relayer)
tokenCancelFee, tokenPriceInXDC := common.Big0, common.Big0
var tokenCancelFee, tokenPriceInXDC *big.Int
if !chain.Config().IsTIPXDCXCancellationFee(header.Number) {
tokenCancelFee = getCancelFeeV1(collateralTokenDecimal, collateralPrice, feeRate, &originOrder)
tokenPriceInXDC = common.Big0
} else {
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
}
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)
lendingBook := lendingstate.GetLendingOrderBookHash(order.LendingToken, order.Term)
lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId)
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 {
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 {
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() {
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)
}
@ -927,7 +928,7 @@ func (l *Lending) LiquidationTrade(lendingStateDB *lendingstate.LendingStateDB,
// cancellation fee = 1/10 borrowing fee
// deprecated after hardfork at TIPXDCXCancellationFee
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 {
// cancel fee = quantityToLend*borrowFee/LendingCancelFee
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 {
return common.Big0, common.Big0
}
cancelFee, tokenPriceInXDC := common.Big0, common.Big0
var cancelFee, tokenPriceInXDC *big.Int
var err error
if order.Side == lendingstate.Investing {
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 {
quoteTokenDecimal, err := l.XDCx.GetTokenDecimal(chain, statedb, quoteToken)
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)
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).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())
}
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 := 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 {
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
}
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)
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)
if tokenBalance.Cmp(quantity) < 0 {
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)
if err != nil {
return err, true, nil
return true, nil, err
}
err = lendingstate.SubTokenBalance(lendingTrade.Borrower, quantity, lendingTrade.CollateralToken, statedb)
if err != nil {
@ -1149,7 +1150,7 @@ func (l *Lending) ProcessTopUpLendingTrade(lendingStateDB *lendingstate.LendingS
newLendingTrade.LiquidationPrice = newLiquidationPrice
newLendingTrade.CollateralLockedAmount = 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) {
@ -1165,7 +1166,7 @@ func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus
if tokenBalance.Cmp(paymentBalance) < 0 {
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{}
var err error
@ -1235,14 +1236,14 @@ func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus
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)
lendingTrade := lendingStateDB.GetLendingTrade(lendingBook, lendingTradeId)
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 {
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).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)
err := tradingStateDb.RemoveLiquidationPrice(tradingstate.GetTradingOrderBookHash(lendingTrade.CollateralToken, lendingTrade.LendingToken), lendingTrade.LiquidationPrice, lendingBook, lendingTrade.TradeId)
if err != nil {
return err, true, nil
return true, nil, err
}
err = lendingstate.AddTokenBalance(lendingTrade.Borrower, recallAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
@ -1268,5 +1269,5 @@ func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.Lending
newLendingTrade.LiquidationPrice = newLiquidationPrice
newLendingTrade.CollateralLockedAmount = newLockedAmount
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 (
"bytes"
"encoding/hex"
"errors"
"fmt"
"log"
"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"
"errors"
"io"
"io/ioutil"
"math/big"
"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
// an encrypted json key stream and the associated passphrase.
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 {
return nil, err
}

View file

@ -32,12 +32,12 @@ var (
// have any code associated with it (i.e. suicided).
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.
ErrNoPendingState = errors.New("backend does not support pending state")
// This error is returned by WaitDeployed if contract creation leaves an
// empty contract behind.
// ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves
// an empty contract behind.
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
// between contract internal errors and the local chain being out of sync.
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.
CallContract(ctx context.Context, call XDPoSChain.CallMsg, blockNumber *big.Int) ([]byte, error)
}
@ -58,6 +59,7 @@ type ContractCaller interface {
type PendingContractCaller interface {
// PendingCodeAt returns the code of the given account in the pending state.
PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error)
// PendingCallContract executes an Ethereum contract call against the pending state.
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
// to the transactor to decide.
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(ctx context.Context, account common.Address) ([]byte, error)
// PendingNonceAt retrieves the current pending nonce associated with an account.
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
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
// 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
// transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default.
EstimateGas(ctx context.Context, call XDPoSChain.CallMsg) (gas uint64, err error)
// SendTransaction injects the transaction into the pending pool for execution.
SendTransaction(ctx context.Context, tx *types.Transaction) error
}

View file

@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
"github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
"github.com/XinFinOrg/XDPoSChain/common"
@ -42,6 +43,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/eth/filters"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/event"
@ -53,7 +55,6 @@ import (
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
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
// 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
a1, err := ks.NewAccount(pass)
if err != nil {
return common.Address{}, nil, fmt.Errorf(err.Error())
return common.Address{}, nil, err
}
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
}
@ -101,7 +102,7 @@ func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64, chainConfi
GasLimit: gasLimit, // need this big, support initial smart contract
Config: chainConfig,
Alloc: alloc,
ExtraData: append(make([]byte, 32), make([]byte, 65)...),
ExtraData: append(make([]byte, 32), make([]byte, crypto.SignatureLength)...),
}
genesis.MustCommit(database)
consensus := XDPoS.NewFaker(database, chainConfig)
@ -160,6 +161,12 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
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
// fresh new state.
func (b *SimulatedBackend) Commit() {
@ -256,6 +263,19 @@ func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common
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.
func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
b.mu.Lock()
@ -276,8 +296,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call XDPoSChain.Cal
if err != nil {
return nil, err
}
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
return rval, err
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
if err != nil {
return nil, err
}
return res.Return(), nil
}
// 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.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
return rval, err
res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
if err != nil {
return nil, err
}
return res.Return(), nil
}
// 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
// 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) {
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
}
@ -325,22 +360,33 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
cap = hi
// 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
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)
if err != nil || failed {
return false
if err != nil {
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
for lo+1 < hi {
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
} else {
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
if hi == cap {
if !executable(hi) {
return 0, errGasEstimationFailed
failed, result, err := executable(hi)
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
@ -357,11 +420,39 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
// callContract implements common code between normal and pending contract calls.
// 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) {
// Ensure message is initialized properly.
if call.GasPrice == nil {
call.GasPrice = big.NewInt(1)
func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.CallMsg, block *types.Block, statedb *state.StateDB) (*core.ExecutionResult, error) {
// Gas prices post 1559 need to be initialized
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
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 {
call.Gas = 50000000
}
@ -379,14 +470,16 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
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
// 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)
owner := common.Address{}
ret, usedGas, failed, err, _ = core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
return
res, err, _ := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
return res, err
}
// 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) 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) 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) Value() *big.Int { return m.CallMsg.Value }
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) {
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) {

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)
Signer SignerFn // Method to use for signing the transaction (mandatory)
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)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
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)
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)
NoSend bool // Do all transact steps but do not send the transaction
}
// 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)
}
// 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) {
var err error
// Ensure a valid value field and resolve the account nonce
func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Address, input []byte, head *types.Header) (*types.Transaction, error) {
// Normalize value
value := opts.Value
if value == nil {
value = new(big.Int)
}
var nonce uint64
if opts.Nonce == nil {
nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From)
// Estimate TipCap
gasTipCap := opts.GasTipCap
if gasTipCap == nil {
tip, err := c.transactor.SuggestGasTipCap(ensureContext(opts.Context))
if err != nil {
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err)
return nil, err
}
} else {
nonce = opts.Nonce.Uint64()
gasTipCap = tip
}
// 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
if gasPrice == nil {
gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context))
price, err := c.transactor.SuggestGasPrice(ensureContext(opts.Context))
if err != nil {
return nil, fmt.Errorf("failed to suggest gas price: %v", err)
return nil, err
}
gasPrice = price
}
// Estimate GasLimit
gasLimit := opts.GasLimit
if gasLimit == 0 {
// Gas estimation cannot succeed without code for method invocations
if contract != nil {
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 opts.GasLimit == 0 {
var err error
gasLimit, err = c.estimateGasLimit(opts, contract, input, gasPrice, nil, nil, value)
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
var rawTx *types.Transaction
if contract == nil {
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input)
} else {
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input)
// create the transaction
nonce, err := c.getNonce(opts)
if err != nil {
return nil, err
}
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 {
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 {
return nil, err
}
if opts.NoSend {
return signedTx, nil
}
if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil {
return nil, err
}
@ -280,7 +388,7 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
if err != nil {
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 {
select {
case logs <- log:
@ -289,11 +397,8 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]int
}
}
return nil
}), nil
})
if err != nil {
return nil, nil, err
}
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 (
LangGo Lang = iota
LangJava
LangObjC
)
// 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{
Type: capitalise(types[i]),
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""),
InputBin: strings.TrimSpace(bytecodes[i]),
Constructor: evmABI.Constructor,
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
// programming language types.
var bindType = map[Lang]func(kind abi.Type) string{
LangGo: bindTypeGo,
LangJava: bindTypeJava,
LangGo: bindTypeGo,
}
// Helper function for the binding generators.
// 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,
// and returns the sizes of these arrays.
//
// (since the inner type is a prefix of the total type declaration),
// 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.
// 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))
}
// 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.
// (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.
@ -311,8 +300,7 @@ func bindUnnestedTypeJava(stringKind string) (int, string) {
// bindTopicType is a set of type binders that convert Solidity types to some
// supported programming language topic types.
var bindTopicType = map[Lang]func(kind abi.Type) string{
LangGo: bindTopicTypeGo,
LangJava: bindTopicTypeJava,
LangGo: bindTopicTypeGo,
}
// 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
}
// 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
// named versions that my be used inside method names.
var namedType = map[Lang]func(string, abi.Type) string{
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
}
}
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
}
// methodNormalizer is a name transformer that modifies Solidity method names to
// conform to target language naming concentions.
var methodNormalizer = map[Lang]func(string) string{
LangGo: capitalise,
LangJava: decapitalise,
LangGo: capitalise,
}
// 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
key, _ := crypto.GenerateKey()
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
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@ -270,7 +270,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, getter, err := DeployGetter(auth, sim)
@ -302,7 +302,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, tupler, err := DeployTupler(auth, sim)
@ -344,7 +344,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, slicer, err := DeploySlicer(auth, sim)
@ -378,7 +378,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, defaulter, err := DeployDefaulter(auth, sim)
@ -447,7 +447,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, limiter, err := DeployFunkyGasPattern(auth, sim)
@ -482,7 +482,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, callfrom, err := DeployCallFrom(auth, sim)
@ -542,7 +542,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, underscorer, err := DeployUnderscorer(auth, sim)
@ -612,7 +612,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, eventer, err := DeployEventer(auth, sim)
@ -761,7 +761,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey()
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
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
@ -821,7 +821,7 @@ func TestBindings(t *testing.T) {
}
t.Log("Using config", params.TestXDPoSMockChainConfig)
// 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)
if err != nil {
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
// programming languages the package can generate to.
var tmplSource = map[Lang]string{
LangGo: tmplSourceGo,
LangJava: tmplSourceJava,
LangGo: tmplSourceGo,
}
// tmplSourceGo is the Go source template use to generate the contract binding
@ -418,105 +417,3 @@ package {{.Package}}
{{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) {
config := *params.TestXDPoSMockChainConfig
config.Eip1559Block = big.NewInt(0)
for name, test := range waitDeployedTests {
backend := backends.NewXDCSimulatedBackend(
core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
}, 10000000, params.TestXDPoSMockChainConfig,
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(100000000000000000)},
}, 10000000, &config,
)
// Create the transaction.
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
// Create the transaction
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)
// 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)
}
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) {
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" {
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)
@ -293,13 +293,13 @@ func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
c := ensureInt(cryptoJSON.KDFParams["c"])
prf := cryptoJSON.KDFParams["prf"].(string)
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)
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?

View file

@ -211,7 +211,7 @@ func testDecryptV3(test KeyStoreTestV3, t *testing.T) {
}
privHex := hex.EncodeToString(privBytes)
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)
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 {
url := u.String()
if len(url) > 32 {
return url[:31] + ""
return url[:31] + ".."
}
return url
}
@ -76,10 +76,9 @@ func (u URL) MarshalJSON() ([]byte, error) {
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
func (u URL) Cmp(url URL) int {
if u.Scheme == url.Scheme {
return strings.Compare(u.Path, url.Path)

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"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
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
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:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+----+---
// E0 | 06 | 00 | 00 | 00 | 04
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+----+---
// E0 | 06 | 00 | 00 | 00 | 04
//
// With no input data, and the output data being:
//
// Description | Length
// ---------------------------------------------------+--------
// Flags 01: arbitrary data signature enabled by user | 1 byte
// Application major version | 1 byte
// Application minor version | 1 byte
// Application patch version | 1 byte
// Description | Length
// ---------------------------------------------------+--------
// Flags 01: arbitrary data signature enabled by user | 1 byte
// Application major version | 1 byte
// Application minor version | 1 byte
// Application patch version | 1 byte
func (w *ledgerDriver) ledgerVersion() ([3]byte, error) {
// Send the request and wait for the response
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:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 02 | 00 return address
// 01 display address and confirm before returning
// | 00: do not return the chain code
// | 01: return the chain code
// | var | 00
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 02 | 00 return address
// 01 display address and confirm before returning
// | 00: do not return the chain code
// | 01: return the chain code
// | var | 00
//
// Where the input data is:
//
// Description | Length
// -------------------------------------------------+--------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
// Description | Length
// -------------------------------------------------+--------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
//
// And the output data is:
//
// Description | Length
// ------------------------+-------------------
// Public Key length | 1 byte
// Uncompressed Public Key | arbitrary
// Ethereum address length | 1 byte
// Ethereum address | 40 bytes hex ascii
// Chain code if requested | 32 bytes
// Description | Length
// ------------------------+-------------------
// Public Key length | 1 byte
// Uncompressed Public Key | arbitrary
// Ethereum address length | 1 byte
// Ethereum address | 40 bytes hex ascii
// Chain code if requested | 32 bytes
func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, error) {
// Flatten the derivation path into the Ledger request
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:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 04 | 00: first transaction data block
// 80: subsequent transaction data block
// | 00 | variable | variable
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+----+-----+---
// E0 | 04 | 00: first transaction data block
// 80: subsequent transaction data block
// | 00 | variable | variable
//
// Where the input for the first transaction block (first 255 bytes) is:
//
// Description | Length
// -------------------------------------------------+----------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
// RLP transaction chunk | arbitrary
// Description | Length
// -------------------------------------------------+----------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
// RLP transaction chunk | arbitrary
//
// And the input for subsequent transaction blocks (first 255 bytes) are:
//
// Description | Length
// ----------------------+----------
// RLP transaction chunk | arbitrary
// Description | Length
// ----------------------+----------
// RLP transaction chunk | arbitrary
//
// And the output data is:
//
// Description | Length
// ------------+---------
// signature V | 1 byte
// signature R | 32 bytes
// signature S | 32 bytes
// Description | Length
// ------------+---------
// signature V | 1 byte
// signature R | 32 bytes
// signature S | 32 bytes
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
path := make([]byte, 1+4*len(derivationPath))
@ -341,7 +342,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
op = ledgerP1ContTransactionData
}
// 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")
}
signature := append(reply[1:], reply[0])
@ -352,7 +353,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
signer = new(types.HomesteadSigner)
} else {
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)
if err != nil {
@ -370,12 +371,12 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
//
// The common transport header is defined as follows:
//
// Description | Length
// --------------------------------------+----------
// Communication channel ID (big endian) | 2 bytes
// Command tag | 1 byte
// Packet sequence index (big endian) | 2 bytes
// Payload | arbitrary
// Description | Length
// --------------------------------------+----------
// Communication channel ID (big endian) | 2 bytes
// Command tag | 1 byte
// Packet sequence index (big endian) | 2 bytes
// Payload | arbitrary
//
// 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
@ -389,15 +390,15 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
//
// APDU Command payloads are encoded as follows:
//
// Description | Length
// -----------------------------------
// APDU length (big endian) | 2 bytes
// APDU CLA | 1 byte
// APDU INS | 1 byte
// APDU P1 | 1 byte
// APDU P2 | 1 byte
// APDU length | 1 byte
// Optional APDU data | arbitrary
// Description | Length
// -----------------------------------
// APDU length (big endian) | 2 bytes
// APDU CLA | 1 byte
// APDU INS | 1 byte
// APDU P1 | 1 byte
// APDU P2 | 1 byte
// APDU length | 1 byte
// Optional APDU data | arbitrary
func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
// Construct the message payload, possibly split into multiple chunks
apdu := make([]byte, 2, 7+len(data))

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/golang/protobuf/proto"
)
@ -222,7 +223,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
} else {
// Trezor backend does not support typed transactions yet.
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

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

View file

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

View file

@ -115,7 +115,7 @@ func doInstall(cmdline []string) {
if minor < 21 {
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.")
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

View file

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

View file

@ -46,17 +46,17 @@ else
log_level=$LOG_LEVEL
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"
../../build/bin/XDC --ethstats ${netstats} --gcmode=archive \
--bootnodes ${bootnodes} --syncmode full \
--datadir ./tmp/xdcchain --networkid 551 \
-port 30303 --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport 8545 \
--rpcapi db,eth,debug,miner,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password ./tmp/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--ws --wsaddr=0.0.0.0 --wsport 8555 \
--wsorigins "*" 2>&1 >>./tmp/xdc.log
--port 30303 --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--http-port 8545 \
--http-api db,eth,debug,miner,net,shh,txpool,personal,web3,XDPoS \
--http-vhosts "*" --unlock "${wallet}" --password ./tmp/.pwd --mine \
--miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--ws --ws-addr=0.0.0.0 --ws-port 8555 \
--ws-origins "*" 2>&1 >>./tmp/xdc.log

View file

@ -24,6 +24,13 @@ do
bootnodes="${bootnodes},$line"
fi
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
if test -z "$LOG_LEVEL"
@ -62,7 +69,7 @@ else
fi
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}"
@ -75,11 +82,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 551 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--http-port $rpc_port \
--http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log
--store-reward \
--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 {
aws = {
source = "hashicorp/aws"
version = "~> 5.13.1"
}
}
}

View file

@ -2,7 +2,6 @@ terraform {
required_providers {
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 {
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.

View file

@ -5,15 +5,6 @@ variable docker_tag {
}
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)
envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] }
logLevel = local.envs["log_level"]
@ -37,12 +28,12 @@ locals {
]
keyNames = {
for r in local.regions :
for r in local.regions :
r.name => [for i in range(r.start, r.end+1) : "xdc${i}"]
}
devnetNodeKeys = {
for r in local.regions :
for r in local.regions :
r.name => { for i in local.keyNames[r.name]: i => local.predefinedNodesConfig[i] }
}
}

View file

@ -24,6 +24,13 @@ do
bootnodes="${bootnodes},$line"
fi
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
if test -z "$LOG_LEVEL"
@ -74,11 +81,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 50 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--http-port $rpc_port \
--http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log
--store-reward \
--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"
}
# WARNING: APSE-1 will only be used to host rpc node
# Workaround to avoid conflicts with existing ecs cluster in existing regions
provider "aws" {
alias = "ap-southeast-1"
region = "ap-southeast-1"
@ -25,9 +23,9 @@ module "devnet_rpc" {
vpc_id = local.vpc_id
aws_subnet_id = local.aws_subnet_id
ami_id = local.ami_id
instance_type = "t3.xlarge"
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
rpc_image = local.rpc_image
volume_size = 1500
providers = {
@ -43,7 +41,7 @@ module "testnet_rpc" {
ami_id = local.ami_id
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
rpc_image = local.rpc_image
volume_size = 1500
providers = {
@ -59,7 +57,7 @@ module "mainnet_rpc" {
ami_id = local.ami_id
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
rpc_image = local.rpc_image
volume_size = 3000
providers = {

View file

@ -1,41 +1,14 @@
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)
envs = { for tuple in regexall("(.*)=(.*)", file(".env")) : tuple[0] => tuple[1] }
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
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
}
locals { //ec2_rpc values
locals {
ami_id = "ami-097c4e1feeea169e5"
rpc_image = "xinfinorg/xdposchain:v2.2.0-beta1"
vpc_id = "vpc-20a06846"

View file

@ -25,6 +25,13 @@ do
bootnodes="${bootnodes},$line"
fi
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
if test -z "$LOG_LEVEL"
@ -76,11 +83,12 @@ XDC --ethstats ${netstats} --gcmode archive \
--nat extip:${INSTANCE_IP} \
--bootnodes ${bootnodes} --syncmode full \
--datadir /work/xdcchain --networkid 51 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \
--http-port $rpc_port \
--http-api db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--miner-gasprice "1" --miner-gaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \
--ws --wsaddr=0.0.0.0 --wsport $ws_port \
--wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log
--store-reward \
--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/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var (
walletCommand = cli.Command{
walletCommand = &cli.Command{
Name: "wallet",
Usage: "Manage XDPoSChain presale wallets",
ArgsUsage: "",
Category: "ACCOUNT COMMANDS",
Description: `
XDC wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.`,
Subcommands: []cli.Command{
Subcommands: []*cli.Command{
{
Name: "import",
Usage: "Import XDPoSChain presale wallet",
ArgsUsage: "<keyFile>",
Action: utils.MigrateFlags(importWallet),
Action: importWallet,
Category: "ACCOUNT COMMANDS",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
@ -65,10 +65,9 @@ passwordfile as argument containing the wallet password in plaintext.`,
},
}
accountCommand = cli.Command{
Name: "account",
Usage: "Manage accounts",
Category: "ACCOUNT COMMANDS",
accountCommand = &cli.Command{
Name: "account",
Usage: "Manage accounts",
Description: `
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.
Make sure you backup your keys regularly.`,
Subcommands: []cli.Command{
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "Print summary of existing accounts",
Action: utils.MigrateFlags(accountList),
Action: accountList,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag,
},
Description: `
@ -104,9 +104,10 @@ Print a short summary of all accounts`,
{
Name: "new",
Usage: "Create a new account",
Action: utils.MigrateFlags(accountCreate),
Action: accountCreate,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
@ -129,10 +130,11 @@ password to file or expose in any other way.
{
Name: "update",
Usage: "Update an existing account",
Action: utils.MigrateFlags(accountUpdate),
Action: accountUpdate,
ArgsUsage: "<address>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag,
utils.LightKDFFlag,
},
@ -158,9 +160,10 @@ changing your password is only possible interactively.
{
Name: "import",
Usage: "Import a private key into a new account",
Action: utils.MigrateFlags(accountImport),
Action: accountImport,
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.KeyStoreDirFlag,
utils.PasswordFileFlag,
utils.LightKDFFlag,
@ -293,7 +296,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
func accountCreate(ctx *cli.Context) error {
cfg := XDCConfig{Node: defaultNodeConfig()}
// Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
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
// one, also providing the possibility to change the pass-phrase.
func accountUpdate(ctx *cli.Context) error {
if len(ctx.Args()) == 0 {
if ctx.Args().Len() == 0 {
utils.Fatalf("No accounts specified to update")
}
stack, _ := makeConfigNode(ctx)
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)
newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, 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 {
keyfile := ctx.Args().First()
if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument")
if ctx.Args().Len() != 1 {
utils.Fatalf("keyfile must be given as the only argument")
}
keyfile := ctx.Args().First()
keyJson, err := os.ReadFile(keyfile)
if err != nil {
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 {
keyfile := ctx.Args().First()
if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument")
if ctx.Args().Len() != 1 {
utils.Fatalf("keyfile must be given as the only argument")
}
keyfile := ctx.Args().First()
key, err := crypto.LoadECDSA(keyfile)
if err != nil {
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) {
XDC := runXDC(t, "account", "list")
datadir := tmpdir(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t, "account", "list", "--datadir", datadir)
XDC.ExpectExit()
}
func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
XDC := runXDC(t, "account", "list", "--datadir", datadir)
defer XDC.ExpectExit()
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(`
defer os.RemoveAll(datadir)
var 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
`)
`
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) {
datadir := tmpDatadirWithKeystore(t)
XDC := runXDC(t, "account", "update",
"--datadir", datadir, "--lightkdf",
"f466859ead1932d743d622cb74fc058882e8648a")
defer os.RemoveAll(datadir)
XDC := runXDC(t, "account", "update", "--datadir", datadir, "--lightkdf", "f466859ead1932d743d622cb74fc058882e8648a")
defer XDC.ExpectExit()
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
@ -107,7 +111,9 @@ Repeat passphrase: {{.InputLine "foobar2"}}
}
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()
XDC.Expect(`
!! 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) {
XDC := runXDC(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer XDC.ExpectExit()
@ -133,10 +169,11 @@ Fatal: could not decrypt key with given passphrase
func TestUnlockFlag(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js")
"js", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--port", "0", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"testdata/empty.js")
XDC.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
@ -157,6 +194,7 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
@ -176,10 +214,11 @@ Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could
// https://github.com/XinFinOrg/XDPoSChain/issues/1785
func TestUnlockFlagMultiIndex(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "0,2",
"js", "testdata/empty.js")
"js", "--datadir", datadir, "--nat", "none", "--nodiscover",
"--maxpeers", "0", "--port", "0", "--unlock", "0,2",
"testdata/empty.js")
XDC.Expect(`
Unlocking account 0 | Attempt 1/3
!! Unsupported terminal, password will be echoed.
@ -203,10 +242,11 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagPasswordFile(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/passwords.txt", "--unlock", "0,2",
"js", "testdata/empty.js")
"js", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--port", "0", "--password", "testdata/passwords.txt", "--unlock", "0,2",
"testdata/empty.js")
XDC.ExpectExit()
wantMessages := []string{
@ -223,6 +263,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
defer os.RemoveAll(datadir)
XDC := runXDC(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--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) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
XDC := runXDC(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js")
"js", "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0",
"--port", "0", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"testdata/empty.js")
defer XDC.ExpectExit()
// 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/params"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
cli "gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var bugCommand = cli.Command{
Action: utils.MigrateFlags(reportBug),
var bugCommand = &cli.Command{
Action: reportBug,
Name: "bug",
Usage: "opens a window to report a bug on the XDC repo",
ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
}
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/event"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/metrics"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var (
initCommand = cli.Command{
Action: utils.MigrateFlags(initGenesis),
initCommand = &cli.Command{
Action: initGenesis,
Name: "init",
Usage: "Bootstrap and initialize a new genesis block",
ArgsUsage: "<genesisPath>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.LightModeFlag,
utils.XDCTestnetFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
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
@ -58,20 +57,32 @@ participating.
It expects the genesis file as argument.`,
}
importCommand = cli.Command{
Action: utils.MigrateFlags(importChain),
importCommand = &cli.Command{
Action: importChain,
Name: "import",
Usage: "Import a blockchain file",
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
utils.GCModeFlag,
utils.CacheDatabaseFlag,
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: `
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.
@ -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,
processing will proceed even if an individual RLP-file import failure occurs.`,
}
exportCommand = cli.Command{
Action: utils.MigrateFlags(exportChain),
exportCommand = &cli.Command{
Action: exportChain,
Name: "export",
Usage: "Export blockchain into file",
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
Requires a first argument of the file to write to.
Optional second and third arguments control the first and
last block to write. In this mode, the file will be appended
if already existing.`,
}
importPreimagesCommand = cli.Command{
Action: utils.MigrateFlags(importPreimages),
importPreimagesCommand = &cli.Command{
Action: importPreimages,
Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
@ -110,57 +122,58 @@ if already existing.`,
Description: `
The import-preimages command imports hash preimages from an RLP encoded stream.`,
}
exportPreimagesCommand = cli.Command{
Action: utils.MigrateFlags(exportPreimages),
exportPreimagesCommand = &cli.Command{
Action: exportPreimages,
Name: "export-preimages",
Usage: "Export the preimage database into an RLP stream",
ArgsUsage: "<dumpfile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
The export-preimages command export hash preimages to an RLP encoded stream`,
}
copydbCommand = cli.Command{
Action: utils.MigrateFlags(copyDb),
copydbCommand = &cli.Command{
Action: copyDb,
Name: "copydb",
Usage: "Create a local chain from a target chaindata folder",
ArgsUsage: "<sourceChaindataDir>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
utils.SyncModeFlag,
utils.FakePoWFlag,
utils.TestnetFlag,
utils.RinkebyFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
The first argument must be the directory containing the blockchain to download from`,
}
removedbCommand = cli.Command{
Action: utils.MigrateFlags(removeDB),
removedbCommand = &cli.Command{
Action: removeDB,
Name: "removedb",
Usage: "Remove blockchain and state databases",
ArgsUsage: " ",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
Remove blockchain and state databases`,
}
dumpCommand = cli.Command{
Action: utils.MigrateFlags(dump),
dumpCommand = &cli.Command{
Action: dump,
Name: "dump",
Usage: "Dump a specific block from storage",
ArgsUsage: "[<blockHash> | <blockNum>]...",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.XDCXDataDirFlag,
utils.CacheFlag,
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
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
func initGenesis(ctx *cli.Context) error {
// Make sure we have a valid genesis JSON
genesisPath := ctx.Args().First()
genesis := new(core.Genesis)
if ctx.GlobalBool(utils.XDCTestnetFlag.Name) {
if len(genesisPath) > 0 {
if ctx.Bool(utils.XDCTestnetFlag.Name) {
if ctx.Args().Len() > 0 {
utils.Fatalf("Flags --apothem and genesis file can't be used at the same time")
}
err := json.Unmarshal(apothemGenesis, &genesis)
@ -187,8 +198,12 @@ func initGenesis(ctx *cli.Context) error {
utils.Fatalf("invalid genesis json: %v", err)
}
} else {
if ctx.Args().Len() != 1 {
utils.Fatalf("need genesis.json file as the only argument")
}
genesisPath := ctx.Args().First()
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)
if err != nil {
@ -203,6 +218,8 @@ func initGenesis(ctx *cli.Context) error {
// Open an initialise both full and light databases
stack, _ := makeFullNode(ctx)
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} {
chaindb, err := stack.OpenDatabase(name, 0, 0, "")
if err != nil {
@ -218,16 +235,15 @@ func initGenesis(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.")
}
stack, cfg := makeFullNode(ctx)
defer stack.Close()
// Start metrics export if enabled
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
utils.SetupMetrics(&cfg.Metrics)
stack, _ := makeFullNode(ctx)
chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close()
@ -249,12 +265,12 @@ func importChain(ctx *cli.Context) error {
// Import the chain
start := time.Now()
if len(ctx.Args()) == 1 {
if ctx.Args().Len() == 1 {
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
log.Error("Import error", "err", err)
}
} else {
for _, arg := range ctx.Args() {
for _, arg := range ctx.Args().Slice() {
if err := utils.ImportChain(chain, arg); err != nil {
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("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) {
if ctx.IsSet(utils.NoCompactionFlag.Name) {
return nil
}
@ -315,17 +331,20 @@ func importChain(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.")
}
stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack)
defer db.Close()
start := time.Now()
var err error
fp := ctx.Args().First()
if len(ctx.Args()) < 3 {
if ctx.Args().Len() < 3 {
err = utils.ExportChain(chain, fp)
} else {
// 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.
func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, _ := makeFullNode(ctx)
defer stack.Close()
diskdb := utils.MakeChainDatabase(ctx, stack)
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.
func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.")
}
stack, _ := makeFullNode(ctx)
defer stack.Close()
diskdb := utils.MakeChainDatabase(ctx, stack)
defer diskdb.Close()
@ -383,19 +407,24 @@ func exportPreimages(ctx *cli.Context) error {
func copyDb(ctx *cli.Context) error {
// 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")
}
// Initialize a new chain for the running node to sync into
stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack)
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)
// 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 {
return err
}
@ -461,10 +490,12 @@ func removeDB(ctx *cli.Context) error {
func dump(ctx *cli.Context) error {
stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack)
defer chainDb.Close()
for _, arg := range ctx.Args() {
for _, arg := range ctx.Args().Slice() {
var block *types.Block
if hashish(arg) {
block = chain.GetBlockByHash(common.HexToHash(arg))

View file

@ -27,34 +27,33 @@ import (
"strings"
"unicode"
"gopkg.in/urfave/cli.v1"
"github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common"
"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/metrics"
"github.com/XinFinOrg/XDPoSChain/node"
"github.com/XinFinOrg/XDPoSChain/params"
whisper "github.com/XinFinOrg/XDPoSChain/whisper/whisperv6"
"github.com/naoina/toml"
"github.com/urfave/cli/v2"
)
var (
dumpConfigCommand = cli.Command{
Action: utils.MigrateFlags(dumpConfig),
dumpConfigCommand = &cli.Command{
Action: dumpConfig,
Name: "dumpconfig",
Usage: "Show configuration values",
ArgsUsage: "",
Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...),
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(nodeFlags, rpcFlags),
Description: `The dumpconfig command shows configuration values.`,
}
configFileFlag = cli.StringFlag{
Name: "config",
Usage: "TOML configuration file",
configFileFlag = &cli.StringFlag{
Name: "config",
Usage: "TOML configuration file",
Category: flags.EthCategory,
}
)
@ -91,9 +90,9 @@ type Bootnodes struct {
type XDCConfig struct {
Eth ethconfig.Config
Shh whisper.Config
Node node.Config
Ethstats ethstatsConfig
Metrics metrics.Config
XDCX XDCx.Config
Account account
StakeEnable bool
@ -120,42 +119,43 @@ func defaultNodeConfig() node.Config {
cfg := node.DefaultConfig
cfg.Name = clientIdentifier
cfg.Version = params.VersionWithCommit(gitCommit)
cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh")
cfg.WSModules = append(cfg.WSModules, "eth", "shh")
cfg.HTTPModules = append(cfg.HTTPModules, "eth")
cfg.WSModules = append(cfg.WSModules, "eth")
cfg.IPCPath = "XDC.ipc"
return cfg
}
// makeConfigNode loads geth configuration and creates a blank node instance.
func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
// Load defaults.
cfg := XDCConfig{
Eth: ethconfig.Defaults,
Shh: whisper.DefaultConfig,
XDCX: XDCx.DefaultConfig,
Node: defaultNodeConfig(),
Metrics: metrics.DefaultConfig,
StakeEnable: true,
Verbosity: 3,
NAT: "",
}
// Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
if ctx.GlobalIsSet(utils.StakingEnabledFlag.Name) {
cfg.StakeEnable = ctx.GlobalBool(utils.StakingEnabledFlag.Name)
}
if !ctx.GlobalIsSet(debug.VerbosityFlag.Name) {
debug.Glogger.Verbosity(log.Lvl(cfg.Verbosity))
if ctx.IsSet(utils.MiningEnabledFlag.Name) {
cfg.StakeEnable = ctx.Bool(utils.MiningEnabledFlag.Name)
}
// 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)
}
// Check testnet is enable.
if ctx.GlobalBool(utils.XDCTestnetFlag.Name) {
if ctx.Bool(utils.XDCTestnetFlag.Name) {
common.IsTestnet = true
common.TRC21IssuerSMC = common.TRC21IssuerSMCTestNet
cfg.Eth.NetworkId = 51
@ -164,24 +164,24 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, XDCConfig) {
common.TIPXDCXCancellationFee = common.TIPXDCXCancellationFeeTestnet
}
if ctx.GlobalBool(utils.EnableXDCPrefixFlag.Name) {
if ctx.Bool(utils.EnableXDCPrefixFlag.Name) {
common.Enable0xPrefix = false
}
// Rewound
if rewound := ctx.GlobalInt(utils.RewoundFlag.Name); rewound != 0 {
if rewound := ctx.Int(utils.RewoundFlag.Name); rewound != 0 {
common.Rewound = uint64(rewound)
}
// 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)
}
// Check GasPrice
common.MinGasPrice = big.NewInt(common.DefaultMinGasPrice)
if ctx.GlobalIsSet(utils.GasPriceFlag.Name) {
if gasPrice := int64(ctx.GlobalInt(utils.GasPriceFlag.Name)); gasPrice > common.DefaultMinGasPrice {
if ctx.IsSet(utils.MinerGasPriceFlag.Name) {
if gasPrice := int64(ctx.Int(utils.MinerGasPriceFlag.Name)); gasPrice > common.DefaultMinGasPrice {
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.SetEthConfig(ctx, stack, &cfg.Eth)
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
if ctx.IsSet(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)
applyMetricConfig(ctx, &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) {
stack, cfg := makeConfigNode(ctx)
// Start metrics export if enabled
utils.SetupMetrics(&cfg.Metrics)
// Register XDCX's OrderBook service if requested.
// enable in default
utils.RegisterXDCXService(stack, &cfg.XDCX)
utils.RegisterEthService(stack, &cfg.Eth)
// 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)
}
utils.RegisterEthService(stack, &cfg.Eth, cfg.Node.Version)
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
@ -287,3 +269,69 @@ func dumpConfig(ctx *cli.Context) error {
os.Stdout.Write(out)
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/node"
"github.com/XinFinOrg/XDPoSChain/rpc"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var (
consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
consoleCommand = cli.Command{
Action: utils.MigrateFlags(localConsole),
Name: "console",
Usage: "Start an interactive JavaScript environment",
Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...),
Category: "CONSOLE COMMANDS",
consoleCommand = &cli.Command{
Action: localConsole,
Name: "console",
Usage: "Start an interactive JavaScript environment",
Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags),
Description: `
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.
See https://github.com/XinFinOrg/XDPoSChain/wiki/JavaScript-Console.`,
}
attachCommand = cli.Command{
Action: utils.MigrateFlags(remoteConsole),
attachCommand = &cli.Command{
Action: remoteConsole,
Name: "attach",
Usage: "Start an interactive JavaScript environment (connect to node)",
ArgsUsage: "[endpoint]",
Flags: append(consoleFlags, utils.DataDirFlag),
Category: "CONSOLE COMMANDS",
Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags),
Description: `
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.
@ -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.`,
}
javascriptCommand = cli.Command{
Action: utils.MigrateFlags(ephemeralConsole),
javascriptCommand = &cli.Command{
Action: ephemeralConsole,
Name: "js",
Usage: "Execute the specified JavaScript files",
ArgsUsage: "<jsfile> [jsfile...]",
Flags: append(nodeFlags, consoleFlags...),
Category: "CONSOLE COMMANDS",
Flags: utils.GroupFlags(nodeFlags, consoleFlags),
Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp
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
node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg)
defer node.Stop()
defer node.Close()
// Attach to the newly started node and start the JavaScript console
client, err := node.Attach()
@ -88,7 +85,7 @@ func localConsole(ctx *cli.Context) error {
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client,
Preload: utils.MakeConsolePreloads(ctx),
}
@ -100,7 +97,7 @@ func localConsole(ctx *cli.Context) error {
defer console.Stop(false)
// 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)
return nil
}
@ -114,17 +111,20 @@ func localConsole(ctx *cli.Context) error {
// remoteConsole will connect to a remote XDC instance, attaching a JavaScript
// console to it.
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()
if endpoint == "" {
path := node.DefaultDataDir()
if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
path = ctx.GlobalString(utils.DataDirFlag.Name)
if ctx.IsSet(utils.DataDirFlag.Name) {
path = ctx.String(utils.DataDirFlag.Name)
}
if path != "" {
if ctx.GlobalBool(utils.TestnetFlag.Name) {
if ctx.Bool(utils.TestnetFlag.Name) {
path = filepath.Join(path, "testnet")
} else if ctx.GlobalBool(utils.RinkebyFlag.Name) {
} else if ctx.Bool(utils.RinkebyFlag.Name) {
path = filepath.Join(path, "rinkeby")
}
}
@ -137,7 +137,7 @@ func remoteConsole(ctx *cli.Context) error {
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client,
Preload: utils.MakeConsolePreloads(ctx),
}
@ -148,7 +148,7 @@ func remoteConsole(ctx *cli.Context) error {
}
defer console.Stop(false)
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script)
return nil
}
@ -181,7 +181,7 @@ func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
node, cfg := makeFullNode(ctx)
startNode(ctx, node, cfg)
defer node.Stop()
defer node.Close()
// Attach to the newly started node and start the JavaScript console
client, err := node.Attach()
@ -190,7 +190,7 @@ func ephemeralConsole(ctx *cli.Context) error {
}
config := console.Config{
DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client,
Preload: utils.MakeConsolePreloads(ctx),
}
@ -202,7 +202,7 @@ func ephemeralConsole(ctx *cli.Context) error {
defer console.Stop(false)
// 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 {
utils.Fatalf("Failed to execute %s: %v", file, err)
}

View file

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

View file

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

View file

@ -28,16 +28,15 @@ import (
"github.com/XinFinOrg/XDPoSChain/eth"
"github.com/XinFinOrg/XDPoSChain/eth/ethconfig"
"github.com/XinFinOrg/XDPoSChain/params"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var (
makecacheCommand = cli.Command{
Action: utils.MigrateFlags(makecache),
makecacheCommand = &cli.Command{
Action: makecache,
Name: "makecache",
Usage: "Generate ethash verification cache (for testing)",
ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: `
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.
`,
}
makedagCommand = cli.Command{
Action: utils.MigrateFlags(makedag),
makedagCommand = &cli.Command{
Action: makedag,
Name: "makedag",
Usage: "Generate ethash mining DAG (for testing)",
ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: `
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.
`,
}
versionCommand = cli.Command{
Action: utils.MigrateFlags(version),
versionCommand = &cli.Command{
Action: version,
Name: "version",
Usage: "Print version numbers",
ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
Description: `
The output of this command is supposed to be machine-readable.
`,
}
licenseCommand = cli.Command{
Action: utils.MigrateFlags(license),
licenseCommand = &cli.Command{
Action: license,
Name: "license",
Usage: "Display license information",
ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
}
)
// makecache generates an ethash verification cache into the provided folder.
func makecache(ctx *cli.Context) error {
args := ctx.Args()
args := ctx.Args().Slice()
if len(args) != 2 {
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.
func makedag(ctx *cli.Context) error {
args := ctx.Args()
args := ctx.Args().Slice()
if len(args) != 2 {
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.TestCmd = cmdtest.NewTestCmd(t, tt)
for i, arg := range args {
switch {
case arg == "-datadir" || arg == "--datadir":
switch arg {
case "--datadir":
if i < len(args)-1 {
tt.Datadir = args[i+1]
}
case arg == "-etherbase" || arg == "--etherbase":
case "--miner-etherbase":
if i < len(args)-1 {
tt.Etherbase = args[i+1]
}
@ -80,7 +80,7 @@ func runXDC(t *testing.T, args ...string) *testXDC {
if tt.Datadir == "" {
tt.Datadir = tmpdir(t)
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.
defer func() {
if t.Failed() {

View file

@ -5,24 +5,24 @@ NAT = "" # flag --nat
[Eth]
NetworkId = 89 # flag --networkid
SyncMode = "full" # flag --syncmode
GasPrice = 1 # flag --gasprice
GasPrice = 1 # flag --miner-gasprice
[Shh]
[Node]
DataDir = "node1/" # flag --datadir
HTTPPort = 8501 # flag --rpcport
HTTPHost = "localhost" # flags --rpcaddr & --rpc
HTTPPort = 8501 # flag --http-port
HTTPHost = "localhost" # flags --http-addr & --http
# in 3 cases :
# HTTPHost is "" == --rpc & --rpcaddr is not set
# HTTPHost is "localhost" or "127.0.0.1" == only set --rpc
# HTTPHost is other IP (ex : 192.168.1.1) = set 2 flags --rpc & --rpcaddr
WSHost = "localhost" # flags --wsaddr & --ws . same option HTTPHost
WSPort = 8546 # flag --wsport
WSModules = ["eth","ssh"] #flag --wsapi
# HTTPHost is "" == --http & --http-addr is not set
# HTTPHost is "localhost" or "127.0.0.1" == only set --http
# HTTPHost is other IP (ex : 192.168.1.1) = set 2 flags --http & --http-addr
WSHost = "localhost" # flags --ws-addr & --ws . same option HTTPHost
WSPort = 8546 # flag --ws-port
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
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 (
"encoding/json"
"flag"
"fmt"
"os"
"strings"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common/compiler"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/urfave/cli/v2"
)
var (
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
// Git SHA1 commit hash of the release (set via linker flags)
gitCommit = ""
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
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)")
app *cli.App
)
func main() {
// Parse and ensure all needed inputs are specified
flag.Parse()
var (
// Flags needed by abigen
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")
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")
os.Exit(-1)
}
if *pkgFlag == "" {
if c.String(pkgFlag.Name) == "" {
fmt.Printf("No destination package specified (--pkg)\n")
os.Exit(-1)
}
var lang bind.Lang
switch *langFlag {
switch c.String(langFlag.Name) {
case "go":
lang = bind.LangGo
case "java":
lang = bind.LangJava
case "objc":
lang = bind.LangObjC
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)
}
// If the entire solidity code was specified, build and bind based on that
@ -74,13 +121,13 @@ func main() {
bins []string
types []string
)
if *solFlag != "" {
if c.String(solFlag.Name) != "" {
// Generate the list of types to exclude from binding
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
}
contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag)
contracts, err := compiler.CompileSolidity(c.String(solcFlag.Name), c.String(solFlag.Name))
if err != nil {
fmt.Printf("Failed to build Solidity contract: %v\n", err)
os.Exit(-1)
@ -99,7 +146,7 @@ func main() {
}
} else {
// 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 {
fmt.Printf("Failed to read input ABI: %v\n", err)
os.Exit(-1)
@ -107,33 +154,43 @@ func main() {
abis = append(abis, string(abi))
bin := []byte{}
if *binFlag != "" {
if bin, err = os.ReadFile(*binFlag); err != nil {
if c.String(binFlag.Name) != "" {
if bin, err = os.ReadFile(c.String(binFlag.Name)); err != nil {
fmt.Printf("Failed to read input bytecode: %v\n", err)
os.Exit(-1)
}
}
bins = append(bins, string(bin))
kind := *typFlag
kind := c.String(typeFlag.Name)
if kind == "" {
kind = *pkgFlag
kind = c.String(pkgFlag.Name)
}
types = append(types, kind)
}
// 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 {
fmt.Printf("Failed to generate ABI binding: %v\n", err)
os.Exit(-1)
}
// 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)
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)
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()
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(*verbosity))
glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.FromLegacyLevel(*verbosity))
glogger.Vmodule(*vmodule)
log.Root().SetHandler(glogger)
log.SetDefault(log.NewLogger(glogger))
natm, err := nat.Parse(*natdesc)
if err != nil {

View file

@ -26,7 +26,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/pborman/uuid"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
type outputGenerate struct {
@ -34,7 +34,14 @@ type outputGenerate struct {
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",
Usage: "generate new 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{
passphraseFlag,
jsonFlag,
cli.StringFlag{
Name: "privatekey",
Usage: "file containing a raw private key to encrypt",
},
privateKeyFlag,
},
Action: func(ctx *cli.Context) error {
// 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/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/crypto"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
type outputInspect struct {
@ -33,7 +33,14 @@ type outputInspect struct {
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",
Usage: "inspect a keyfile",
ArgsUsage: "<keyfile>",
@ -45,10 +52,7 @@ make sure to use this feature with great caution!`,
Flags: []cli.Flag{
passphraseFlag,
jsonFlag,
cli.BoolFlag{
Name: "private",
Usage: "include the private key in the output",
},
privateFlag,
},
Action: func(ctx *cli.Context) error {
keyfilepath := ctx.Args().First()

View file

@ -20,8 +20,8 @@ import (
"fmt"
"os"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"gopkg.in/urfave/cli.v1"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/urfave/cli/v2"
)
const (
@ -34,8 +34,8 @@ var gitCommit = ""
var app *cli.App
func init() {
app = utils.NewApp(gitCommit, "an Ethereum key manager")
app.Commands = []cli.Command{
app = flags.NewApp(gitCommit, "an Ethereum key manager")
app.Commands = []*cli.Command{
commandGenerate,
commandInspect,
commandSignMessage,
@ -45,15 +45,15 @@ func init() {
// Commonly used command line flags.
var (
passphraseFlag = cli.StringFlag{
passphraseFlag = &cli.StringFlag{
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",
Usage: "output JSON instead of human-readable format",
}
messageFlag = cli.StringFlag{
messageFlag = &cli.StringFlag{
Name: "message",
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/common"
"github.com/XinFinOrg/XDPoSChain/crypto"
"gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
type outputSign struct {
Signature string
}
var msgfileFlag = cli.StringFlag{
var msgfileFlag = &cli.StringFlag{
Name: "msgfile",
Usage: "file containing the message to sign/verify",
}
var commandSignMessage = cli.Command{
var commandSignMessage = &cli.Command{
Name: "signmessage",
Usage: "sign a message",
ArgsUsage: "<keyfile> <message>",
@ -88,7 +88,7 @@ type outputVerify struct {
RecoveredPublicKey string
}
var commandVerifyMessage = cli.Command{
var commandVerifyMessage = &cli.Command{
Name: "verifymessage",
Usage: "verify the signature of a signed 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 {
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.")
}
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)
}
return msg
} else if len(ctx.Args()) == msgarg+1 {
} else if ctx.NArg() == msgarg+1 {
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
}

View file

@ -25,7 +25,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/console"
"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

View file

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

View file

@ -23,10 +23,10 @@ import (
"strings"
"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,
Name: "disasm",
Usage: "disassembles evm binary",
@ -34,17 +34,22 @@ var disasmCommand = cli.Command{
}
func disasmCmd(ctx *cli.Context) error {
if len(ctx.Args().First()) == 0 {
return errors.New("filename required")
var in string
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()
in, err := os.ReadFile(fn)
if err != nil {
return err
}
code := strings.TrimSpace(string(in[:]))
code := strings.TrimSpace(in)
fmt.Printf("%v\n", code)
return asm.PrintDisassembled(code)
}

View file

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

View file

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

View file

@ -24,13 +24,11 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/tests"
cli "gopkg.in/urfave/cli.v1"
"github.com/urfave/cli/v2"
)
var stateTestCommand = cli.Command{
var stateTestCommand = &cli.Command{
Action: stateTestCmd,
Name: "statetest",
Usage: "executes the given state tests",
@ -49,25 +47,24 @@ func stateTestCmd(ctx *cli.Context) error {
if len(ctx.Args().First()) == 0 {
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
config := &vm.LogConfig{
EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name),
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
}
var (
tracer vm.EVMLogger
debugger *vm.StructLogger
)
switch {
case ctx.GlobalBool(MachineFlag.Name):
case ctx.Bool(MachineFlag.Name):
tracer = vm.NewJSONLogger(config, os.Stderr)
case ctx.GlobalBool(DebugFlag.Name):
case ctx.Bool(DebugFlag.Name):
debugger = vm.NewStructLogger(config)
tracer = debugger
@ -86,7 +83,7 @@ func stateTestCmd(ctx *cli.Context) error {
// Iterate over all the tests, run them and aggregate the results
cfg := vm.Config{
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))
for key, test := range tests {
@ -97,20 +94,20 @@ func stateTestCmd(ctx *cli.Context) error {
if err != nil {
// Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error()
if ctx.GlobalBool(DumpFlag.Name) && state != nil {
if ctx.Bool(DumpFlag.Name) && state != nil {
dump := state.RawDump()
result.State = &dump
}
}
// 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))
}
results = append(results, *result)
// Print any structured logs collected
if ctx.GlobalBool(DebugFlag.Name) {
if ctx.Bool(DebugFlag.Name) {
if debugger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####")
vm.WriteTrace(os.Stderr, debugger.StructLogs())

View file

@ -94,7 +94,7 @@ var (
func main() {
// Parse the flags and set up the logger to print everything requested
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
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.
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
@ -396,7 +396,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
continue
}
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)
return
}
@ -433,7 +433,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
}
if !result.Success {
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)
return
}
@ -462,7 +462,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
case *noauthFlag:
username, avatar, address, err = authNoAuth(msg.URL)
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 = 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
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)
return
}
@ -657,7 +657,7 @@ func sendSuccess(conn *wsConn, msg string) error {
func authGitHub(url string) (string, string, common.Address, error) {
// Retrieve the gist from the GitHub Gist APIs
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 != "" {
req.SetBasicAuth(*githubUser, *githubToken)
}
@ -679,7 +679,7 @@ func authGitHub(url string) (string, string, common.Address, error) {
return "", "", common.Address{}, err
}
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
var address common.Address
@ -690,7 +690,7 @@ func authGitHub(url string) (string, string, common.Address, error) {
}
}
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
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()
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
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
parts := strings.Split(url, "/")
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
// 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
parts = strings.Split(res.Request.URL.String(), "/")
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]
@ -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)))
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
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
parts := strings.Split(url, "/")
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]
@ -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)))
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
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
parts := strings.Split(url, "/")
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]
@ -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)))
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
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) {
address := common.HexToAddress(regexp.MustCompile("0x[0-9a-fA-F]{40}").FindString(url))
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
}

View file

@ -92,15 +92,15 @@ func faucetHtml() (*asset, error) {
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
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 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).
@ -130,29 +130,29 @@ func MustAssetString(name string) string {
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
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 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
// error if the asset could not be found or the digest could not be loaded.
func AssetDigest(name string) ([sha256.Size]byte, error) {
canonicalName := strings.Replace(name, "\\", "/", -1)
canonicalName := strings.ReplaceAll(name, "\\", "/")
if f, ok := _bindata[canonicalName]; ok {
a, err := f()
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 [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.
@ -203,17 +203,17 @@ const AssetDebug = false
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
canonicalName := strings.Replace(name, "\\", "/", -1)
canonicalName := strings.ReplaceAll(name, "\\", "/")
pathList := strings.Split(canonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
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 {
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))
for childName := range node.Children {
@ -270,6 +270,6 @@ func RestoreAssets(dir, name string) error {
}
func _filePath(dir, name string) string {
canonicalName := strings.Replace(name, "\\", "/", -1)
canonicalName := strings.ReplaceAll(name, "\\", "/")
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/common"
"github.com/XinFinOrg/XDPoSChain/common/lru"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state"
@ -20,7 +21,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/ethdb/leveldb"
"github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/XinFinOrg/XDPoSChain/trie"
"github.com/XinFinOrg/XDPoSChain/common/lru"
)
var (
@ -170,7 +170,7 @@ func getAllChilds(n StateNode, db *leveldb.Database) ([17]*StateNode, error) {
}
if err == nil {
childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))}
} else if err != nil {
} else {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err
@ -187,7 +187,7 @@ func getAllChilds(n StateNode, db *leveldb.Database) ([17]*StateNode, error) {
}
if err == nil {
childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)}
} else if err != nil {
} else {
_, ok := err.(*trie.MissingNodeError)
if !ok {
return childs, err

View file

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

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