all: remove mongodb support in XDCx (#1679)

* all: remove SDK node

* cmd: remove XDCXDBEngineFlag

* cmd: remove XDCXDBConnectionUrlFlag

* cmd, XDCx: remove XDCXDBReplicaSetNameFlag

* XDCx: remove ConnectionUrl

* all: remove mongodb support

* cmd: remove XDCXEnabledFlag
This commit is contained in:
Daniel Liu 2025-11-15 19:20:02 +08:00 committed by GitHub
parent 0c96e76992
commit 71e8e27f84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 15 additions and 2097 deletions

View file

@ -5,7 +5,6 @@ import (
"fmt"
"math/big"
"strconv"
"time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxDAO"
@ -30,11 +29,8 @@ var (
)
type Config struct {
DataDir string `toml:",omitempty"`
DBEngine string `toml:",omitempty"`
DBName string `toml:",omitempty"`
ConnectionUrl string `toml:",omitempty"`
ReplicaSetName string `toml:",omitempty"`
DataDir string `toml:",omitempty"`
DBName string `toml:",omitempty"`
}
// DefaultConfig represents (shocker!) the default configuration.
@ -45,7 +41,6 @@ var DefaultConfig = Config{
type XDCX struct {
// Order related
db XDCxDAO.XDCXDAO
mongodb XDCxDAO.XDCXDAO
Triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
StateCache tradingstate.Database // State database to reuse between imports (contains state cache) *XDCx_state.TradingStateDB
@ -60,16 +55,6 @@ func NewLDBEngine(cfg *Config) *XDCxDAO.BatchDatabase {
return batchDB
}
func NewMongoDBEngine(cfg *Config) *XDCxDAO.MongoDatabase {
mongoDB, err := XDCxDAO.NewMongoDatabase(nil, cfg.DBName, cfg.ConnectionUrl, cfg.ReplicaSetName, 0)
if err != nil {
log.Crit("Failed to init mongodb engine", "err", err)
}
return mongoDB
}
func New(stack *node.Node, cfg *Config) *XDCX {
XDCX := &XDCX{
Triegc: prque.New[int64, common.Hash](nil),
@ -79,30 +64,16 @@ func New(stack *node.Node, cfg *Config) *XDCX {
// default DBEngine: levelDB
XDCX.db = NewLDBEngine(cfg)
XDCX.sdkNode = false
if cfg.DBEngine == "mongodb" { // this is an add-on DBEngine for SDK nodes
XDCX.mongodb = NewMongoDBEngine(cfg)
XDCX.sdkNode = true
}
XDCX.StateCache = tradingstate.NewDatabase(XDCX.db)
return XDCX
}
func (XDCx *XDCX) IsSDKNode() bool {
return XDCx.sdkNode
}
func (XDCx *XDCX) GetLevelDB() XDCxDAO.XDCXDAO {
return XDCx.db
}
func (XDCx *XDCX) GetMongoDB() XDCxDAO.XDCXDAO {
return XDCx.mongodb
}
func (XDCx *XDCX) ProcessOrderPending(header *types.Header, coinbase common.Address, chain consensus.ChainContext, pending map[common.Address]types.OrderTransactions, statedb *state.StateDB, XDCXstatedb *tradingstate.TradingStateDB) ([]tradingstate.TxDataMatch, map[common.Hash]tradingstate.MatchingResult) {
txMatches := []tradingstate.TxDataMatch{}
matchingResults := map[common.Hash]tradingstate.MatchingResult{}
@ -250,259 +221,6 @@ func (XDCx *XDCX) ConvertXDCToToken(chain consensus.ChainContext, statedb *state
return tokenQuantity, tokenPriceInXDC, nil
}
// there are 3 tasks need to complete to update data in SDK nodes after matching
// 1. txMatchData.Order: order has been processed. This order should be put to `orders` collection with status sdktypes.OrderStatusOpen
// 2. txMatchData.Trades: includes information of matched orders.
// a. PutObject them to `trades` collection
// b. Update status of regrading orders to sdktypes.OrderStatusFilled
func (XDCx *XDCX) SyncDataToSDKNode(takerOrderInTx *tradingstate.OrderItem, txHash common.Hash, txMatchTime time.Time, statedb *state.StateDB, trades []map[string]string, rejectedOrders []*tradingstate.OrderItem, dirtyOrderCount *uint64) error {
var (
// originTakerOrder: order get from db, nil if it doesn't exist
// takerOrderInTx: order decoded from txdata
// updatedTakerOrder: order with new status, filledAmount, CreatedAt, UpdatedAt. This will be inserted to db
originTakerOrder, updatedTakerOrder *tradingstate.OrderItem
makerDirtyHashes []string
makerDirtyFilledAmount map[string]*big.Int
err error
)
db := XDCx.GetMongoDB()
db.InitBulk()
if takerOrderInTx.Status == tradingstate.OrderStatusCancelled && len(rejectedOrders) > 0 {
// cancel order is rejected -> nothing change
log.Debug("Cancel order is rejected", "order", tradingstate.ToJSON(takerOrderInTx))
return nil
}
// 1. put processed takerOrderInTx to db
lastState := tradingstate.OrderHistoryItem{}
val, err := db.GetObject(takerOrderInTx.Hash, &tradingstate.OrderItem{})
if err == nil && val != nil {
originTakerOrder = val.(*tradingstate.OrderItem)
lastState = tradingstate.OrderHistoryItem{
TxHash: originTakerOrder.TxHash,
FilledAmount: tradingstate.CloneBigInt(originTakerOrder.FilledAmount),
Status: originTakerOrder.Status,
UpdatedAt: originTakerOrder.UpdatedAt,
}
}
if originTakerOrder != nil {
updatedTakerOrder = originTakerOrder
} else {
updatedTakerOrder = takerOrderInTx
updatedTakerOrder.FilledAmount = new(big.Int)
}
if takerOrderInTx.Status != tradingstate.OrderStatusCancelled {
updatedTakerOrder.Status = tradingstate.OrderStatusOpen
} else {
updatedTakerOrder.Status = tradingstate.OrderStatusCancelled
updatedTakerOrder.ExtraData = takerOrderInTx.ExtraData
}
updatedTakerOrder.TxHash = txHash
if updatedTakerOrder.CreatedAt.IsZero() {
updatedTakerOrder.CreatedAt = txMatchTime
}
if txMatchTime.Before(updatedTakerOrder.UpdatedAt) || (txMatchTime.Equal(updatedTakerOrder.UpdatedAt) && *dirtyOrderCount == 0) {
log.Debug("Ignore old orders/trades taker", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", updatedTakerOrder.UpdatedAt.UnixNano())
return nil
}
*dirtyOrderCount++
XDCx.UpdateOrderCache(updatedTakerOrder.BaseToken, updatedTakerOrder.QuoteToken, updatedTakerOrder.Hash, txHash, lastState)
updatedTakerOrder.UpdatedAt = txMatchTime
// 2. put trades to db and update status to FILLED
log.Debug("Got trades", "number", len(trades), "txhash", txHash.Hex())
makerDirtyFilledAmount = make(map[string]*big.Int)
for _, trade := range trades {
// 2.a. put to trades
if trade == nil {
continue
}
tradeRecord := &tradingstate.Trade{}
quantity := tradingstate.ToBigInt(trade[tradingstate.TradeQuantity])
price := tradingstate.ToBigInt(trade[tradingstate.TradePrice])
if price.Sign() <= 0 || quantity.Sign() <= 0 {
return fmt.Errorf("trade misses important information. tradedPrice %v, tradedQuantity %v", price, quantity)
}
tradeRecord.Amount = quantity
tradeRecord.PricePoint = price
tradeRecord.BaseToken = updatedTakerOrder.BaseToken
tradeRecord.QuoteToken = updatedTakerOrder.QuoteToken
tradeRecord.Status = tradingstate.TradeStatusSuccess
tradeRecord.Taker = updatedTakerOrder.UserAddress
tradeRecord.Maker = common.HexToAddress(trade[tradingstate.TradeMaker])
tradeRecord.TakerOrderHash = updatedTakerOrder.Hash
tradeRecord.MakerOrderHash = common.HexToHash(trade[tradingstate.TradeMakerOrderHash])
tradeRecord.TxHash = txHash
tradeRecord.TakerOrderSide = updatedTakerOrder.Side
tradeRecord.TakerExchange = updatedTakerOrder.ExchangeAddress
tradeRecord.MakerExchange = common.HexToAddress(trade[tradingstate.TradeMakerExchange])
tradeRecord.MakeFee, _ = new(big.Int).SetString(trade[tradingstate.MakerFee], 10)
tradeRecord.TakeFee, _ = new(big.Int).SetString(trade[tradingstate.TakerFee], 10)
// set makerOrderType, takerOrderType
tradeRecord.MakerOrderType = trade[tradingstate.MakerOrderType]
tradeRecord.TakerOrderType = updatedTakerOrder.Type
if tradeRecord.CreatedAt.IsZero() {
tradeRecord.CreatedAt = txMatchTime
}
tradeRecord.UpdatedAt = txMatchTime
tradeRecord.Hash = tradeRecord.ComputeHash()
log.Debug("TRADE history", "amount", tradeRecord.Amount, "pricepoint", tradeRecord.PricePoint,
"taker", tradeRecord.Taker.Hex(), "maker", tradeRecord.Maker.Hex(), "takerOrder", tradeRecord.TakerOrderHash.Hex(), "makerOrder", tradeRecord.MakerOrderHash.Hex(),
"takerFee", tradeRecord.TakeFee, "makerFee", tradeRecord.MakeFee)
if err := db.PutObject(tradeRecord.Hash, tradeRecord); err != nil {
return fmt.Errorf("SDKNode: failed to store tradeRecord %s", err.Error())
}
// 2.b. update status and filledAmount
filledAmount := quantity
// maker dirty order
makerFilledAmount := big.NewInt(0)
if amount, ok := makerDirtyFilledAmount[trade[tradingstate.TradeMakerOrderHash]]; ok {
makerFilledAmount = tradingstate.CloneBigInt(amount)
}
makerFilledAmount = new(big.Int).Add(makerFilledAmount, filledAmount)
makerDirtyFilledAmount[trade[tradingstate.TradeMakerOrderHash]] = makerFilledAmount
makerDirtyHashes = append(makerDirtyHashes, trade[tradingstate.TradeMakerOrderHash])
//updatedTakerOrder = XDCx.updateMatchedOrder(updatedTakerOrder, filledAmount, txMatchTime, txHash)
// update filledAmount, status of takerOrder
updatedTakerOrder.FilledAmount = new(big.Int).Add(updatedTakerOrder.FilledAmount, filledAmount)
if updatedTakerOrder.FilledAmount.Cmp(updatedTakerOrder.Quantity) < 0 && updatedTakerOrder.Type == tradingstate.Limit {
updatedTakerOrder.Status = tradingstate.OrderStatusPartialFilled
} else {
updatedTakerOrder.Status = tradingstate.OrderStatusFilled
}
}
// for Market orders
// filledAmount > 0 : FILLED
// otherwise: REJECTED
if updatedTakerOrder.Type == tradingstate.Market {
if updatedTakerOrder.FilledAmount.Sign() > 0 {
updatedTakerOrder.Status = tradingstate.OrderStatusFilled
} else {
updatedTakerOrder.Status = tradingstate.OrderStatusRejected
}
}
log.Debug("PutObject processed takerOrder",
"userAddr", updatedTakerOrder.UserAddress.Hex(), "side", updatedTakerOrder.Side,
"price", updatedTakerOrder.Price, "quantity", updatedTakerOrder.Quantity, "filledAmount", updatedTakerOrder.FilledAmount, "status", updatedTakerOrder.Status,
"hash", updatedTakerOrder.Hash.Hex(), "txHash", updatedTakerOrder.TxHash.Hex())
if err := db.PutObject(updatedTakerOrder.Hash, updatedTakerOrder); err != nil {
return fmt.Errorf("SDKNode: failed to put processed takerOrder. Hash: %s Error: %s", updatedTakerOrder.Hash.Hex(), err.Error())
}
items := db.GetListItemByHashes(makerDirtyHashes, &tradingstate.OrderItem{})
if items != nil {
makerOrders := items.([]*tradingstate.OrderItem)
log.Debug("Maker dirty orders", "len", len(makerOrders), "txhash", txHash.Hex())
for _, o := range makerOrders {
if txMatchTime.Before(o.UpdatedAt) {
log.Debug("Ignore old orders/trades maker", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", updatedTakerOrder.UpdatedAt.UnixNano())
continue
}
lastState = tradingstate.OrderHistoryItem{
TxHash: o.TxHash,
FilledAmount: tradingstate.CloneBigInt(o.FilledAmount),
Status: o.Status,
UpdatedAt: o.UpdatedAt,
}
XDCx.UpdateOrderCache(o.BaseToken, o.QuoteToken, o.Hash, txHash, lastState)
o.TxHash = txHash
o.UpdatedAt = txMatchTime
o.FilledAmount = new(big.Int).Add(o.FilledAmount, makerDirtyFilledAmount[o.Hash.Hex()])
if o.FilledAmount.Cmp(o.Quantity) < 0 {
o.Status = tradingstate.OrderStatusPartialFilled
} else {
o.Status = tradingstate.OrderStatusFilled
}
log.Debug("PutObject processed makerOrder",
"userAddr", o.UserAddress.Hex(), "side", o.Side,
"price", o.Price, "quantity", o.Quantity, "filledAmount", o.FilledAmount, "status", o.Status,
"hash", o.Hash.Hex(), "txHash", o.TxHash.Hex())
if err := db.PutObject(o.Hash, o); err != nil {
return fmt.Errorf("SDKNode: failed to put processed makerOrder. Hash: %s Error: %s", o.Hash.Hex(), err.Error())
}
}
}
// 3. put rejected orders to db and update status REJECTED
log.Debug("Got rejected orders", "number", len(rejectedOrders), "rejectedOrders", rejectedOrders)
if len(rejectedOrders) > 0 {
var rejectedHashes []string
// updateRejectedOrders
for _, rejectedOrder := range rejectedOrders {
rejectedHashes = append(rejectedHashes, rejectedOrder.Hash.Hex())
if updatedTakerOrder.Hash == rejectedOrder.Hash && !txMatchTime.Before(updatedTakerOrder.UpdatedAt) {
// cache order history for handling reorg
orderHistoryRecord := tradingstate.OrderHistoryItem{
TxHash: updatedTakerOrder.TxHash,
FilledAmount: tradingstate.CloneBigInt(updatedTakerOrder.FilledAmount),
Status: updatedTakerOrder.Status,
UpdatedAt: updatedTakerOrder.UpdatedAt,
}
XDCx.UpdateOrderCache(updatedTakerOrder.BaseToken, updatedTakerOrder.QuoteToken, updatedTakerOrder.Hash, txHash, orderHistoryRecord)
// if whole order is rejected, status = REJECTED
// otherwise, status = FILLED
if updatedTakerOrder.FilledAmount.Sign() > 0 {
updatedTakerOrder.Status = tradingstate.OrderStatusFilled
} else {
updatedTakerOrder.Status = tradingstate.OrderStatusRejected
}
updatedTakerOrder.TxHash = txHash
updatedTakerOrder.UpdatedAt = txMatchTime
if err := db.PutObject(updatedTakerOrder.Hash, updatedTakerOrder); err != nil {
return fmt.Errorf("SDKNode: failed to reject takerOrder. Hash: %s Error: %s", updatedTakerOrder.Hash.Hex(), err.Error())
}
}
}
items := db.GetListItemByHashes(rejectedHashes, &tradingstate.OrderItem{})
if items != nil {
dirtyRejectedOrders := items.([]*tradingstate.OrderItem)
for _, order := range dirtyRejectedOrders {
if txMatchTime.Before(order.UpdatedAt) {
log.Debug("Ignore old orders/trades reject", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", updatedTakerOrder.UpdatedAt.UnixNano())
continue
}
// cache order history for handling reorg
orderHistoryRecord := tradingstate.OrderHistoryItem{
TxHash: order.TxHash,
FilledAmount: tradingstate.CloneBigInt(order.FilledAmount),
Status: order.Status,
UpdatedAt: order.UpdatedAt,
}
XDCx.UpdateOrderCache(order.BaseToken, order.QuoteToken, order.Hash, txHash, orderHistoryRecord)
dirtyFilledAmount, ok := makerDirtyFilledAmount[order.Hash.Hex()]
if ok && dirtyFilledAmount != nil {
order.FilledAmount = new(big.Int).Add(order.FilledAmount, dirtyFilledAmount)
}
// if whole order is rejected, status = REJECTED
// otherwise, status = FILLED
if order.FilledAmount.Sign() > 0 {
order.Status = tradingstate.OrderStatusFilled
} else {
order.Status = tradingstate.OrderStatusRejected
}
order.TxHash = txHash
order.UpdatedAt = txMatchTime
if err = db.PutObject(order.Hash, order); err != nil {
return fmt.Errorf("SDKNode: failed to update rejectedOder to sdkNode %s", err.Error())
}
}
}
}
if err := db.CommitBulk(); err != nil {
return fmt.Errorf("SDKNode fail to commit bulk update orders, trades at txhash %s . Error: %s", txHash.Hex(), err.Error())
}
return nil
}
func (XDCx *XDCX) GetTradingState(block *types.Block, author common.Address) (*tradingstate.TradingStateDB, error) {
root, err := XDCx.GetTradingStateRoot(block, author)
if err != nil {
@ -559,45 +277,3 @@ func (XDCx *XDCX) UpdateOrderCache(baseToken, quoteToken common.Address, orderHa
}
XDCx.orderCache.Add(txhash, orderCacheAtTxHash)
}
func (XDCx *XDCX) RollbackReorgTxMatch(txhash common.Hash) error {
db := XDCx.GetMongoDB()
db.InitBulk()
items := db.GetListItemByTxHash(txhash, &tradingstate.OrderItem{})
if items != nil {
for _, order := range items.([]*tradingstate.OrderItem) {
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
}
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))
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
}
order.TxHash = orderHistoryItem.TxHash
order.Status = orderHistoryItem.Status
order.FilledAmount = tradingstate.CloneBigInt(orderHistoryItem.FilledAmount)
order.UpdatedAt = orderHistoryItem.UpdatedAt
log.Debug("XDCx reorg: update order to the last orderHistoryItem", "order", tradingstate.ToJSON(order), "orderHistoryItem", orderHistoryItem)
if err := db.PutObject(order.Hash, order); err != nil {
log.Crit("SDKNode: failed to update reorg order", "err", err.Error(), "order", tradingstate.ToJSON(order))
}
}
}
log.Debug("XDCx reorg: DeleteTradeByTxHash", "txhash", txhash.Hex())
db.DeleteItemByTxHash(txhash, &tradingstate.Trade{})
if err := db.CommitBulk(); err != nil {
return fmt.Errorf("failed to RollbackTradingData. %v", err)
}
return nil
}

View file

@ -784,37 +784,5 @@ func (XDCx *XDCX) UpdateMediumPriceBeforeEpoch(epochNumber uint64, tradingStateD
}
tradingStateDB.SetMediumPrice(orderbook, tradingstate.Zero, tradingstate.Zero)
}
if XDCx.IsSDKNode() {
if err := XDCx.LogEpochPrice(epochNumber, epochPriceResult); err != nil {
log.Error("failed to update epochPrice", "err", err)
}
}
return nil
}
// put average price of epoch to mongodb for tracking liquidation trades
// epochPriceResult: a map of epoch average price, key is orderbook hash , value is epoch average price
// orderbook hash genereted from baseToken, quoteToken at XDPoSChain/XDCx/tradingstate/common.go:214
func (XDCx *XDCX) LogEpochPrice(epochNumber uint64, epochPriceResult map[common.Hash]*big.Int) error {
db := XDCx.GetMongoDB()
db.InitBulk()
for orderbook, price := range epochPriceResult {
if price.Sign() <= 0 {
continue
}
epochPriceItem := &tradingstate.EpochPriceItem{
Epoch: epochNumber,
Orderbook: orderbook,
Price: price,
}
epochPriceItem.Hash = epochPriceItem.ComputeHash()
if err := db.PutObject(epochPriceItem.Hash, epochPriceItem); err != nil {
return err
}
}
if err := db.CommitBulk(); err != nil {
return err
}
return nil
}

View file

@ -2,6 +2,7 @@
// This file is part of the Core XDPoSChain infrastructure
// https://XDPoSChain.com
// Package XDCxDAO provides an interface to work with XDCx database, including leveldb for masternode and mongodb for SDK node
package XDCxDAO
import (
@ -15,15 +16,7 @@ type XDCXDAO interface {
// for both leveldb and mongodb
IsEmptyKey(key []byte) bool
Close() error
// mongodb methods
HasObject(hash common.Hash, val interface{}) (bool, error)
GetObject(hash common.Hash, val interface{}) (interface{}, error)
PutObject(hash common.Hash, val interface{}) error
DeleteObject(hash common.Hash, val interface{}) error // won't return error if key not found
GetListItemByTxHash(txhash common.Hash, val interface{}) interface{}
GetListItemByHashes(hashes []string, val interface{}) interface{}
DeleteItemByTxHash(txhash common.Hash, val interface{})
// basic XDCx
InitBulk()

View file

@ -52,26 +52,10 @@ func (db *BatchDatabase) IsEmptyKey(key []byte) bool {
return len(key) == 0 || bytes.Equal(key, db.emptyKey)
}
func (db *BatchDatabase) HasObject(hash common.Hash, val interface{}) (bool, error) {
// for mongodb only
return false, nil
}
func (db *BatchDatabase) GetObject(hash common.Hash, val interface{}) (interface{}, error) {
// for mongodb only
return nil, nil
}
func (db *BatchDatabase) PutObject(hash common.Hash, val interface{}) error {
// for mongodb only
return nil
}
func (db *BatchDatabase) DeleteObject(hash common.Hash, val interface{}) error {
// for mongodb only
return nil
}
func (db *BatchDatabase) Put(key []byte, val []byte) error {
return db.db.Put(key, val)
}

View file

@ -1,920 +0,0 @@
package XDCxDAO
import (
"bytes"
"encoding/hex"
"fmt"
"strings"
"time"
"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"
)
const (
ordersCollection = "orders"
tradesCollection = "trades"
lendingItemsCollection = "lending_items"
lendingTradesCollection = "lending_trades"
lendingTopUpCollection = "lending_topups"
lendingRepayCollection = "lending_repays"
lendingRecallCollection = "lending_recalls"
epochPriceCollection = "epoch_prices"
)
type MongoDatabase struct {
Session *mgo.Session
dbName string
emptyKey []byte
cacheItems *lru.Cache[string, interface{}] // Cache for reading
orderBulk *mgo.Bulk
tradeBulk *mgo.Bulk
epochPriceBulk *mgo.Bulk
lendingItemBulk *mgo.Bulk
topUpBulk *mgo.Bulk
recallBulk *mgo.Bulk
repayBulk *mgo.Bulk
lendingTradeBulk *mgo.Bulk
}
// InitSession initializes a new session with mongodb
func NewMongoDatabase(session *mgo.Session, dbName string, mongoURL string, replicaSetName string, cacheLimit int) (*MongoDatabase, error) {
if session == nil {
// in case of multiple database instances
hosts := strings.Split(mongoURL, ",")
dbInfo := &mgo.DialInfo{
Addrs: hosts,
Database: dbName,
ReplicaSetName: replicaSetName,
Timeout: 30 * time.Second,
}
ns, err := mgo.DialWithInfo(dbInfo)
if err != nil {
return nil, err
}
session = ns
}
itemCacheLimit := defaultCacheLimit
if cacheLimit > 0 {
itemCacheLimit = cacheLimit
}
db := &MongoDatabase{
Session: session,
dbName: dbName,
cacheItems: lru.NewCache[string, interface{}](itemCacheLimit),
}
if err := db.EnsureIndexes(); err != nil {
return nil, err
}
return db, nil
}
func (db *MongoDatabase) IsEmptyKey(key []byte) bool {
return len(key) == 0 || bytes.Equal(key, db.emptyKey)
}
func (db *MongoDatabase) getCacheKey(key []byte) string {
return hex.EncodeToString(key)
}
func (db *MongoDatabase) HasObject(hash common.Hash, val interface{}) (bool, error) {
if db.IsEmptyKey(hash.Bytes()) {
return false, nil
}
cacheKey := db.getCacheKey(hash.Bytes())
if db.cacheItems.Contains(cacheKey) {
return true, nil
}
sc := db.Session.Copy()
defer sc.Close()
var (
count int
err error
)
query := bson.M{"hash": hash.Hex()}
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()
if err != nil {
return false, err
}
if count == 1 {
return true, nil
}
case *tradingstate.Trade:
// Find key in tradesCollection collection
count, err = sc.DB(db.dbName).C(tradesCollection).Find(query).Limit(1).Count()
if err != nil {
return false, err
}
if count == 1 {
return true, nil
}
case *lendingstate.LendingItem:
// Find key in lendingItemsCollection collection
switch item.Type {
case lendingstate.Repay:
count, err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).Limit(1).Count()
case lendingstate.TopUp:
count, err = sc.DB(db.dbName).C(lendingTopUpCollection).Find(query).Limit(1).Count()
case lendingstate.Recall:
count, err = sc.DB(db.dbName).C(lendingRecallCollection).Find(query).Limit(1).Count()
default:
count, err = sc.DB(db.dbName).C(lendingItemsCollection).Find(query).Limit(1).Count()
}
if err != nil {
return false, err
}
if count == 1 {
return true, nil
}
case *lendingstate.LendingTrade:
// Find key in lendingTradesCollection collection
count, err = sc.DB(db.dbName).C(lendingTradesCollection).Find(query).Limit(1).Count()
if err != nil {
return false, err
}
if count == 1 {
return true, nil
}
}
return false, nil
}
func (db *MongoDatabase) GetObject(hash common.Hash, val interface{}) (interface{}, error) {
if db.IsEmptyKey(hash.Bytes()) {
return nil, nil
}
cacheKey := db.getCacheKey(hash.Bytes())
if cached, ok := db.cacheItems.Get(cacheKey); ok {
return cached, nil
} else {
sc := db.Session.Copy()
defer sc.Close()
query := bson.M{"hash": hash.Hex()}
switch item := val.(type) {
case *tradingstate.OrderItem:
var oi *tradingstate.OrderItem
err := sc.DB(db.dbName).C(ordersCollection).Find(query).One(&oi)
if err != nil {
return nil, err
}
db.cacheItems.Add(cacheKey, oi)
return oi, nil
case *tradingstate.Trade:
var t *tradingstate.Trade
err := sc.DB(db.dbName).C(tradesCollection).Find(query).One(&t)
if err != nil {
return nil, err
}
db.cacheItems.Add(cacheKey, t)
return t, nil
case *lendingstate.LendingItem:
var li *lendingstate.LendingItem
var err error
switch item.Type {
case lendingstate.Repay:
err = sc.DB(db.dbName).C(lendingRepayCollection).Find(query).One(&li)
case lendingstate.TopUp:
err = sc.DB(db.dbName).C(lendingTopUpCollection).Find(query).One(&li)
case lendingstate.Recall:
err = sc.DB(db.dbName).C(lendingRecallCollection).Find(query).One(&li)
default:
err = sc.DB(db.dbName).C(lendingItemsCollection).Find(query).One(&li)
}
if err != nil {
return nil, err
}
db.cacheItems.Add(cacheKey, li)
return li, nil
case *lendingstate.LendingTrade:
var t *lendingstate.LendingTrade
err := sc.DB(db.dbName).C(lendingTradesCollection).Find(query).One(&t)
if err != nil {
return nil, err
}
db.cacheItems.Add(cacheKey, t)
return t, nil
default:
return nil, nil
}
}
}
func (db *MongoDatabase) PutObject(hash common.Hash, val interface{}) error {
cacheKey := db.getCacheKey(hash.Bytes())
db.cacheItems.Add(cacheKey, val)
switch item := val.(type) {
case *tradingstate.Trade:
// PutObject trade into tradesCollection collection
db.tradeBulk.Insert(item)
case *tradingstate.OrderItem:
// PutObject order into ordersCollection collection
if item.Status == tradingstate.OrderStatusOpen {
db.orderBulk.Insert(item)
} else {
query := bson.M{"hash": item.Hash.Hex()}
db.orderBulk.Upsert(query, item)
}
return nil
case *tradingstate.EpochPriceItem:
query := bson.M{"hash": item.Hash.Hex()}
db.epochPriceBulk.Upsert(query, item)
return nil
case *lendingstate.LendingTrade:
// PutObject LendingTrade into tradesCollection collection
if existed, err := db.HasObject(hash, val); err == nil && existed {
query := bson.M{"hash": item.Hash.Hex()}
db.lendingTradeBulk.Upsert(query, item)
} else {
db.lendingTradeBulk.Insert(item)
}
case *lendingstate.LendingItem:
// PutObject order into ordersCollection collection
switch item.Type {
case lendingstate.Repay:
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.Repay
}
db.repayBulk.Insert(item)
return nil
case lendingstate.TopUp:
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.TopUp
}
db.topUpBulk.Insert(item)
return nil
case lendingstate.Recall:
if item.Status != lendingstate.LendingStatusReject {
item.Status = lendingstate.Recall
}
db.recallBulk.Insert(item)
return nil
default:
if item.Status == lendingstate.LendingStatusOpen {
db.lendingItemBulk.Insert(item)
} else {
query := bson.M{"hash": item.Hash.Hex()}
db.lendingItemBulk.Upsert(query, item)
}
return nil
}
default:
log.Error("PutObject: unknown type of object", "val", val)
}
return nil
}
func (db *MongoDatabase) DeleteObject(hash common.Hash, val interface{}) error {
cacheKey := db.getCacheKey(hash.Bytes())
db.cacheItems.Remove(cacheKey)
sc := db.Session.Copy()
defer sc.Close()
query := bson.M{"hash": hash.Hex()}
found, err := db.HasObject(hash, val)
if err != nil {
return err
}
if found {
var err error
switch item := val.(type) {
case *tradingstate.OrderItem:
err = sc.DB(db.dbName).C(ordersCollection).Remove(query)
if err != nil && err != mgo.ErrNotFound {
return fmt.Errorf("failed to delete orderItem. Err: %v", err)
}
case *tradingstate.Trade:
err = sc.DB(db.dbName).C(tradesCollection).Remove(query)
if err != nil && err != mgo.ErrNotFound {
return fmt.Errorf("failed to delete XDCx trade. Err: %v", err)
}
case *lendingstate.LendingItem:
switch item.Type {
case lendingstate.Repay:
err = sc.DB(db.dbName).C(lendingRepayCollection).Remove(query)
case lendingstate.TopUp:
err = sc.DB(db.dbName).C(lendingTopUpCollection).Remove(query)
case lendingstate.Recall:
err = sc.DB(db.dbName).C(lendingRecallCollection).Remove(query)
default:
err = sc.DB(db.dbName).C(lendingItemsCollection).Remove(query)
}
if err != nil && err != mgo.ErrNotFound {
return fmt.Errorf("failed to delete lendingItem. Err: %v", err)
}
case *lendingstate.LendingTrade:
err = sc.DB(db.dbName).C(lendingTradesCollection).Remove(query)
if err != nil && err != mgo.ErrNotFound {
return fmt.Errorf("failed to delete lendingTrade. Err: %v", err)
}
}
}
return nil
}
func (db *MongoDatabase) InitBulk() {
sc := db.Session
db.orderBulk = sc.DB(db.dbName).C(ordersCollection).Bulk()
db.tradeBulk = sc.DB(db.dbName).C(tradesCollection).Bulk()
db.epochPriceBulk = sc.DB(db.dbName).C(epochPriceCollection).Bulk()
}
func (db *MongoDatabase) InitLendingBulk() {
sc := db.Session
db.lendingItemBulk = sc.DB(db.dbName).C(lendingItemsCollection).Bulk()
db.lendingTradeBulk = sc.DB(db.dbName).C(lendingTradesCollection).Bulk()
db.topUpBulk = sc.DB(db.dbName).C(lendingTopUpCollection).Bulk()
db.repayBulk = sc.DB(db.dbName).C(lendingRepayCollection).Bulk()
db.recallBulk = sc.DB(db.dbName).C(lendingRecallCollection).Bulk()
}
func (db *MongoDatabase) CommitBulk() error {
if _, err := db.orderBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.tradeBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.epochPriceBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
return nil
}
func (db *MongoDatabase) CommitLendingBulk() error {
if _, err := db.lendingItemBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.lendingTradeBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.topUpBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.repayBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
if _, err := db.recallBulk.Run(); err != nil && !mgo.IsDup(err) {
return err
}
return nil
}
func (db *MongoDatabase) Put(key []byte, val []byte) error {
// for levelDB only
return nil
}
func (db *MongoDatabase) Delete(key []byte) error {
// for levelDB only
return nil
}
func (db *MongoDatabase) Has(key []byte) (bool, error) {
// for levelDB only
return false, nil
}
func (db *MongoDatabase) Get(key []byte) ([]byte, error) {
// for levelDB only
return nil, nil
}
func (db *MongoDatabase) DeleteItemByTxHash(txhash common.Hash, val interface{}) {
sc := db.Session.Copy()
defer sc.Close()
query := bson.M{"txHash": txhash.Hex()}
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)
}
case *tradingstate.Trade:
if err := sc.DB(db.dbName).C(tradesCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete trade", "txhash", txhash, "err", err)
}
case *lendingstate.LendingItem:
switch item.Type {
case lendingstate.Repay:
if err := sc.DB(db.dbName).C(lendingRepayCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete repayItem", "txhash", txhash, "err", err)
}
return
case lendingstate.TopUp:
if err := sc.DB(db.dbName).C(lendingTopUpCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete topupItem", "txhash", txhash, "err", err)
}
return
case lendingstate.Recall:
if err := sc.DB(db.dbName).C(lendingRecallCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete recallItem", "txhash", txhash, "err", err)
}
return
default:
if err := sc.DB(db.dbName).C(lendingItemsCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete lendingItem", "txhash", txhash, "err", err)
}
return
}
case *lendingstate.LendingTrade:
if err := sc.DB(db.dbName).C(lendingTradesCollection).Remove(query); err != nil && err != mgo.ErrNotFound {
log.Error("DeleteItemByTxHash: failed to delete lendingTrade", "txhash", txhash, "err", err)
}
default:
log.Error("DeleteItemByTxHash: Unknown object type", "txhash", txhash, "object", val)
}
}
func (db *MongoDatabase) GetListItemByTxHash(txhash common.Hash, val interface{}) interface{} {
sc := db.Session.Copy()
defer sc.Close()
query := bson.M{"txHash": txhash.Hex()}
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 {
log.Error("failed to GetListItemByTxHash (orders)", "err", err, "Txhash", txhash)
}
return result
case *tradingstate.Trade:
result := []*tradingstate.Trade{}
if err := sc.DB(db.dbName).C(tradesCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (trades)", "err", err, "Txhash", txhash)
}
return result
case *lendingstate.LendingItem:
result := []*lendingstate.LendingItem{}
switch item.Type {
case lendingstate.Repay:
if err := sc.DB(db.dbName).C(lendingRepayCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (repayItems)", "err", err, "txhash", txhash)
}
return result
case lendingstate.TopUp:
if err := sc.DB(db.dbName).C(lendingTopUpCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (topupItems)", "err", err, "txhash", txhash)
}
return result
case lendingstate.Recall:
if err := sc.DB(db.dbName).C(lendingRecallCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (recallItems)", "err", err, "txhash", txhash)
}
return result
default:
if err := sc.DB(db.dbName).C(lendingItemsCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (lendingItems)", "err", err, "txhash", txhash)
}
return result
}
case *lendingstate.LendingTrade:
result := []*lendingstate.LendingTrade{}
if err := sc.DB(db.dbName).C(lendingTradesCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByTxHash (lendingTrades)", "err", err, "Txhash", txhash)
}
return result
default:
log.Error("GetListItemByTxHash: Unknown object type", "txhash", txhash, "object", val)
}
return nil
}
func (db *MongoDatabase) GetListItemByHashes(hashes []string, val interface{}) interface{} {
sc := db.Session.Copy()
defer sc.Close()
query := bson.M{"hash": bson.M{"$in": hashes}}
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 {
log.Error("failed to GetListItemByHashes (orders)", "err", err, "hashes", hashes)
}
return result
case *tradingstate.Trade:
result := []*tradingstate.Trade{}
if err := sc.DB(db.dbName).C(tradesCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (trades)", "err", err, "hashes", hashes)
}
return result
case *lendingstate.LendingItem:
result := []*lendingstate.LendingItem{}
switch item.Type {
case lendingstate.Repay:
if err := sc.DB(db.dbName).C(lendingRepayCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (repayItems)", "err", err, "hashes", hashes)
}
return result
case lendingstate.TopUp:
if err := sc.DB(db.dbName).C(lendingTopUpCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (topupItems)", "err", err, "hashes", hashes)
}
return result
case lendingstate.Recall:
if err := sc.DB(db.dbName).C(lendingRecallCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (recallItems)", "err", err, "hashes", hashes)
}
return result
default:
if err := sc.DB(db.dbName).C(lendingItemsCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (lendingItems)", "err", err, "hashes", hashes)
}
return result
}
case *lendingstate.LendingTrade:
result := []*lendingstate.LendingTrade{}
if err := sc.DB(db.dbName).C(lendingTradesCollection).Find(query).All(&result); err != nil && err != mgo.ErrNotFound {
log.Error("failed to GetListItemByHashes (lendingTrades)", "err", err, "hashes", hashes)
}
return result
default:
log.Error("GetListItemByHashes: Unknown object type", "hashes", hashes, "object", val)
}
return nil
}
func (db *MongoDatabase) EnsureIndexes() error {
orderHashIndex := mgo.Index{
Key: []string{"hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_order_hash",
}
orderTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_order_tx_hash",
}
tradeHashIndex := mgo.Index{
Key: []string{"hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_trade_hash",
}
tradeTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_trade_tx_hash",
}
lendingItemHashIndex := mgo.Index{
Key: []string{"hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_item_hash",
}
lendingItemTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_item_tx_hash",
}
lendingTradeHashIndex := mgo.Index{
Key: []string{"hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_trade_hash",
}
lendingTradeTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_trade_tx_hash",
}
repayHashIndex := mgo.Index{
Key: []string{"hash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_repay_hash",
}
repayTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_repay_tx_hash",
}
repayUniqueIndex := mgo.Index{
Key: []string{"txHash", "hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_repay_unique",
}
recallHashIndex := mgo.Index{
Key: []string{"hash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_recall_hash",
}
recallTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_recall_tx_hash",
}
recallUniqueIndex := mgo.Index{
Key: []string{"txHash", "hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_recall_unique",
}
topupHashIndex := mgo.Index{
Key: []string{"hash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_topup_hash",
}
topupTxHashIndex := mgo.Index{
Key: []string{"txHash"},
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_topup_tx_hash",
}
topUpUniqueIndex := mgo.Index{
Key: []string{"txHash", "hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_lending_topup_unique",
}
epochPriceIndex := mgo.Index{
Key: []string{"hash"},
Unique: true,
DropDups: true,
Background: true,
Sparse: true,
Name: "index_epoch_price",
}
sc := db.Session.Copy()
defer sc.Close()
indexes, _ := sc.DB(db.dbName).C(ordersCollection).Indexes()
if !existingIndex(orderHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(ordersCollection).EnsureIndex(orderHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", orderHashIndex.Name, err)
}
}
if !existingIndex(orderTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(ordersCollection).EnsureIndex(orderTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", orderTxHashIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(tradesCollection).Indexes()
if !existingIndex(tradeHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(tradesCollection).EnsureIndex(tradeHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", tradeHashIndex.Name, err)
}
}
if !existingIndex(tradeTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(tradesCollection).EnsureIndex(tradeTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", tradeTxHashIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(lendingItemsCollection).Indexes()
if !existingIndex(lendingItemHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingItemsCollection).EnsureIndex(lendingItemHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", lendingItemHashIndex.Name, err)
}
}
if !existingIndex(lendingItemTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingItemsCollection).EnsureIndex(lendingItemTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", lendingItemTxHashIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(lendingTradesCollection).Indexes()
if !existingIndex(lendingTradeHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingTradesCollection).EnsureIndex(lendingTradeHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", lendingTradeHashIndex.Name, err)
}
}
if !existingIndex(lendingTradeTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingTradesCollection).EnsureIndex(lendingTradeTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", lendingTradeTxHashIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(lendingRepayCollection).Indexes()
if !existingIndex(repayHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRepayCollection).EnsureIndex(repayHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", repayHashIndex.Name, err)
}
}
if !existingIndex(repayTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRepayCollection).EnsureIndex(repayTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", repayTxHashIndex.Name, err)
}
}
if !existingIndex(repayUniqueIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRepayCollection).EnsureIndex(repayUniqueIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", repayUniqueIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(lendingRecallCollection).Indexes()
if !existingIndex(recallHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRecallCollection).EnsureIndex(recallHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", recallHashIndex.Name, err)
}
}
if !existingIndex(recallTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRecallCollection).EnsureIndex(recallTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", recallTxHashIndex.Name, err)
}
}
if !existingIndex(recallUniqueIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingRecallCollection).EnsureIndex(repayUniqueIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", repayUniqueIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(lendingTopUpCollection).Indexes()
if !existingIndex(topupHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingTopUpCollection).EnsureIndex(topupHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", topupHashIndex.Name, err)
}
}
if !existingIndex(topupTxHashIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingTopUpCollection).EnsureIndex(topupTxHashIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", topupTxHashIndex.Name, err)
}
}
if !existingIndex(topUpUniqueIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(lendingTopUpCollection).EnsureIndex(repayUniqueIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", repayUniqueIndex.Name, err)
}
}
indexes, _ = sc.DB(db.dbName).C(epochPriceCollection).Indexes()
if !existingIndex(epochPriceIndex.Name, indexes) {
if err := sc.DB(db.dbName).C(epochPriceCollection).EnsureIndex(epochPriceIndex); err != nil {
return fmt.Errorf("failed to create index %s . Err: %v", epochPriceIndex.Name, err)
}
}
return nil
}
func (db *MongoDatabase) Close() error {
if db.Session != nil {
db.Session.Close()
}
return nil
}
// HasAncient returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) HasAncient(kind string, number uint64) (bool, error) {
return false, errNotSupported
}
// Ancient returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) Ancient(kind string, number uint64) ([]byte, error) {
return nil, errNotSupported
}
// Ancients returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) Ancients() (uint64, error) {
return 0, errNotSupported
}
// AncientSize returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) AncientSize(kind string) (uint64, error) {
return 0, errNotSupported
}
// AppendAncient returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) AppendAncient(number uint64, hash, header, body, receipts, td []byte) error {
return errNotSupported
}
// TruncateAncients returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) TruncateAncients(items uint64) error {
return errNotSupported
}
// Sync returns an error as we don't have a backing chain freezer.
func (db *MongoDatabase) Sync() error {
return errNotSupported
}
func (db *MongoDatabase) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
panic("NewIterator from XDCxDAO mongodb is not supported")
}
func (db *MongoDatabase) Stat(property string) (string, error) {
return "", errNotSupported
}
func (db *MongoDatabase) Compact(start []byte, limit []byte) error {
return errNotSupported
}
func (db *MongoDatabase) NewBatch() ethdb.Batch {
// for levelDB only
return nil
}
func (db *MongoDatabase) NewBatchWithSize(size int) ethdb.Batch {
return nil
}
type Batch struct {
collection string
}
func (b *Batch) Put(key, value []byte) error {
// for levelDB only
return nil
}
func (b *Batch) Write() error {
// for levelDB only
return nil
}
func (b *Batch) ValueSize() int {
// for levelDB only
return int(0)
}
func (b *Batch) Reset() {
// for levelDB only
}
func existingIndex(indexName string, indexes []mgo.Index) bool {
if len(indexes) == 0 {
return false
}
for _, index := range indexes {
if index.Name == indexName {
return true
}
}
return false
}

View file

@ -3,10 +3,8 @@ package XDCxlending
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"strconv"
"time"
"github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
@ -56,10 +54,6 @@ func (l *Lending) GetLevelDB() XDCxDAO.XDCXDAO {
return l.XDCx.GetLevelDB()
}
func (l *Lending) GetMongoDB() XDCxDAO.XDCXDAO {
return l.XDCx.GetMongoDB()
}
func (l *Lending) ProcessOrderPending(header *types.Header, coinbase common.Address, chain consensus.ChainContext, pending map[common.Address]types.LendingTransactions, statedb *state.StateDB, lendingStatedb *lendingstate.LendingStateDB, tradingStateDb *tradingstate.TradingStateDB) ([]*lendingstate.LendingItem, map[common.Hash]lendingstate.MatchingResult) {
lendingItems := []*lendingstate.LendingItem{}
matchingResults := map[common.Hash]lendingstate.MatchingResult{}
@ -151,474 +145,6 @@ func (l *Lending) ProcessOrderPending(header *types.Header, coinbase common.Addr
return lendingItems, matchingResults
}
// there are 3 tasks need to complete (for SDK nodes) after matching
// 1. Put takerLendingItem to database
// 2.a Update status, filledAmount of makerLendingItem
// 2.b. Put lendingTrade to database
// 3. Update status of rejected items
func (l *Lending) SyncDataToSDKNode(chain consensus.ChainContext, statedb *state.StateDB, block *types.Block, takerLendingItem *lendingstate.LendingItem, txHash common.Hash, txMatchTime time.Time, trades []*lendingstate.LendingTrade, rejectedItems []*lendingstate.LendingItem, dirtyOrderCount *uint64) error {
var (
// originTakerLendingItem: item getting from database
originTakerLendingItem, updatedTakerLendingItem *lendingstate.LendingItem
makerDirtyHashes []string
makerDirtyFilledAmount map[string]*big.Int
err error
)
db := l.GetMongoDB()
db.InitLendingBulk()
if takerLendingItem.Status == lendingstate.LendingStatusCancelled && len(rejectedItems) > 0 {
// cancel order is rejected -> nothing change
log.Debug("Cancel order is rejected", "order", lendingstate.ToJSON(takerLendingItem))
return nil
}
// 1. put processed takerLendingItem to database
lastState := lendingstate.LendingItemHistoryItem{}
// Typically, takerItem has never existed in database
// except cancel case: in this case, item existed in database with status = OPEN, then use send another lendingItem to cancel it
val, err := db.GetObject(takerLendingItem.Hash, &lendingstate.LendingItem{Type: takerLendingItem.Type})
if err == nil && val != nil {
originTakerLendingItem = val.(*lendingstate.LendingItem)
lastState = lendingstate.LendingItemHistoryItem{
TxHash: originTakerLendingItem.TxHash,
FilledAmount: lendingstate.CloneBigInt(originTakerLendingItem.FilledAmount),
Status: originTakerLendingItem.Status,
UpdatedAt: originTakerLendingItem.UpdatedAt,
}
}
if originTakerLendingItem != nil {
updatedTakerLendingItem = originTakerLendingItem
} else {
updatedTakerLendingItem = takerLendingItem
updatedTakerLendingItem.FilledAmount = new(big.Int)
}
if takerLendingItem.Status == lendingstate.LendingStatusNew {
updatedTakerLendingItem.Status = lendingstate.LendingStatusOpen
} else if takerLendingItem.Status == lendingstate.LendingStatusCancelled {
updatedTakerLendingItem.Status = lendingstate.LendingStatusCancelled
updatedTakerLendingItem.ExtraData = takerLendingItem.ExtraData
}
updatedTakerLendingItem.TxHash = txHash
if updatedTakerLendingItem.CreatedAt.IsZero() {
updatedTakerLendingItem.CreatedAt = txMatchTime
}
if txMatchTime.Before(updatedTakerLendingItem.UpdatedAt) || (txMatchTime.Equal(updatedTakerLendingItem.UpdatedAt) && *dirtyOrderCount == 0) {
log.Debug("Ignore old lendingItem/lendingTrades taker", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", updatedTakerLendingItem.UpdatedAt.UnixNano())
return nil
}
*dirtyOrderCount++
l.UpdateLendingItemCache(updatedTakerLendingItem.LendingToken, updatedTakerLendingItem.CollateralToken, updatedTakerLendingItem.Hash, txHash, lastState)
updatedTakerLendingItem.UpdatedAt = txMatchTime
// 2. put trades to database and update status
log.Debug("Got lendingTrades", "number", len(trades), "txhash", txHash.Hex())
makerDirtyFilledAmount = make(map[string]*big.Int)
tradeList := map[common.Hash]*lendingstate.LendingTrade{}
for _, tradeRecord := range trades {
// 2.a. put to trades
if tradeRecord == nil {
continue
}
if updatedTakerLendingItem.Type == lendingstate.Repay || updatedTakerLendingItem.Type == lendingstate.TopUp || updatedTakerLendingItem.Type == lendingstate.Recall {
// repay, topup: assign hash = trade.hash
updatedTakerLendingItem.Hash = tradeRecord.Hash
updatedTakerLendingItem.CollateralToken = tradeRecord.CollateralToken
updatedTakerLendingItem.FilledAmount = updatedTakerLendingItem.Quantity
updatedTakerLendingItem.Interest = new(big.Int).SetUint64(tradeRecord.Interest)
switch updatedTakerLendingItem.Type {
case lendingstate.TopUp:
updatedTakerLendingItem.Status = lendingstate.TopUp
extraData, _ := json.Marshal(struct {
Price *big.Int
}{
Price: new(big.Int).Div(new(big.Int).Mul(tradeRecord.LiquidationPrice, tradeRecord.DepositRate), tradeRecord.LiquidationRate),
})
updatedTakerLendingItem.ExtraData = string(extraData)
// manual topUp item
updatedTakerLendingItem.AutoTopUp = false
case lendingstate.Repay:
updatedTakerLendingItem.Status = lendingstate.Repay
paymentBalance := lendingstate.CalculateTotalRepayValue(block.Time(), tradeRecord.LiquidationTime, tradeRecord.Term, tradeRecord.Interest, tradeRecord.Amount)
updatedTakerLendingItem.Quantity = paymentBalance
updatedTakerLendingItem.FilledAmount = paymentBalance
// manual repay item
updatedTakerLendingItem.AutoTopUp = false
case lendingstate.Recall:
updatedTakerLendingItem.Status = lendingstate.Recall
// manual recall item
updatedTakerLendingItem.AutoTopUp = false
}
log.Debug("UpdateLendingTrade:", "type", updatedTakerLendingItem.Type, "hash", tradeRecord.Hash.Hex(), "status", tradeRecord.Status, "tradeId", tradeRecord.TradeId)
tradeList[tradeRecord.Hash] = tradeRecord
continue
}
if tradeRecord.CreatedAt.IsZero() {
tradeRecord.CreatedAt = txMatchTime
}
tradeRecord.UpdatedAt = txMatchTime
tradeRecord.TxHash = txHash
tradeRecord.Hash = tradeRecord.ComputeHash()
tradeList[tradeRecord.Hash] = tradeRecord
// 2.b. update status and filledAmount
filledAmount := new(big.Int)
if tradeRecord.Amount != nil {
filledAmount = lendingstate.CloneBigInt(tradeRecord.Amount)
}
// maker dirty order
makerFilledAmount := big.NewInt(0)
var makerOrderHash common.Hash
if updatedTakerLendingItem.Side == lendingstate.Borrowing {
makerOrderHash = tradeRecord.InvestingOrderHash
} else {
makerOrderHash = tradeRecord.BorrowingOrderHash
}
if amount, ok := makerDirtyFilledAmount[makerOrderHash.Hex()]; ok {
makerFilledAmount = lendingstate.CloneBigInt(amount)
}
makerFilledAmount = new(big.Int).Add(makerFilledAmount, filledAmount)
makerDirtyFilledAmount[makerOrderHash.Hex()] = makerFilledAmount
makerDirtyHashes = append(makerDirtyHashes, makerOrderHash.Hex())
if updatedTakerLendingItem.Type == lendingstate.Limit || updatedTakerLendingItem.Type == lendingstate.Market {
//updatedTakerOrder = l.updateMatchedOrder(updatedTakerOrder, filledAmount, txMatchTime, txHash)
// update filledAmount, status of takerOrder
updatedTakerLendingItem.FilledAmount = new(big.Int).Add(updatedTakerLendingItem.FilledAmount, filledAmount)
if updatedTakerLendingItem.FilledAmount.Cmp(updatedTakerLendingItem.Quantity) < 0 && updatedTakerLendingItem.Type == lendingstate.Limit {
updatedTakerLendingItem.Status = lendingstate.LendingStatusPartialFilled
} else {
updatedTakerLendingItem.Status = lendingstate.LendingStatusFilled
}
}
}
if err := l.UpdateLendingTrade(tradeList, txHash, txMatchTime); err != nil {
return err
}
// for Market orders
// filledAmount > 0 : FILLED
// otherwise: REJECTED
if updatedTakerLendingItem.Type == lendingstate.Market {
if updatedTakerLendingItem.FilledAmount.Sign() > 0 {
updatedTakerLendingItem.Status = lendingstate.LendingStatusFilled
} else {
updatedTakerLendingItem.Status = lendingstate.LendingStatusReject
}
}
log.Debug("PutObject processed takerLendingItem",
"term", updatedTakerLendingItem.Term, "userAddr", updatedTakerLendingItem.UserAddress.Hex(), "side", updatedTakerLendingItem.Side,
"Interest", updatedTakerLendingItem.Interest, "quantity", updatedTakerLendingItem.Quantity, "filledAmount", updatedTakerLendingItem.FilledAmount, "status", updatedTakerLendingItem.Status,
"hash", updatedTakerLendingItem.Hash.Hex(), "txHash", updatedTakerLendingItem.TxHash.Hex())
if !(updatedTakerLendingItem.Type == lendingstate.Repay || updatedTakerLendingItem.Type == lendingstate.TopUp || updatedTakerLendingItem.Type == lendingstate.Recall) || updatedTakerLendingItem.Status != lendingstate.LendingStatusOpen {
if err := db.PutObject(updatedTakerLendingItem.Hash, updatedTakerLendingItem); err != nil {
return fmt.Errorf("SDKNode: failed to put processed takerOrder. Hash: %s Error: %s", updatedTakerLendingItem.Hash.Hex(), err.Error())
}
}
items := db.GetListItemByHashes(makerDirtyHashes, &lendingstate.LendingItem{})
if items != nil {
makerItems := items.([]*lendingstate.LendingItem)
log.Debug("Maker dirty lendingItem", "len", len(makerItems), "txhash", txHash.Hex())
for _, m := range makerItems {
if txMatchTime.Before(m.UpdatedAt) {
log.Debug("Ignore old lendingItem/lendingTrades maker", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", m.UpdatedAt.UnixNano())
continue
}
lastState = lendingstate.LendingItemHistoryItem{
TxHash: m.TxHash,
FilledAmount: lendingstate.CloneBigInt(m.FilledAmount),
Status: m.Status,
UpdatedAt: m.UpdatedAt,
}
l.UpdateLendingItemCache(m.LendingToken, m.CollateralToken, m.Hash, txHash, lastState)
m.TxHash = txHash
m.UpdatedAt = txMatchTime
m.FilledAmount = new(big.Int).Add(m.FilledAmount, makerDirtyFilledAmount[m.Hash.Hex()])
if m.FilledAmount.Cmp(m.Quantity) < 0 {
m.Status = lendingstate.LendingStatusPartialFilled
} else {
m.Status = lendingstate.LendingStatusFilled
}
log.Debug("PutObject processed makerLendingItem",
"term", m.Term, "userAddr", m.UserAddress.Hex(), "side", m.Side,
"Interest", m.Interest, "quantity", m.Quantity, "filledAmount", m.FilledAmount, "status", m.Status,
"hash", m.Hash.Hex(), "txHash", m.TxHash.Hex())
if err := db.PutObject(m.Hash, m); err != nil {
return fmt.Errorf("SDKNode: failed to put processed makerOrder. Hash: %s Error: %s", m.Hash.Hex(), err.Error())
}
}
}
// 3. put rejected orders to leveldb and update status REJECTED
log.Debug("Got rejected lendingItems", "number", len(rejectedItems), "rejectedLendingItems", rejectedItems)
if len(rejectedItems) > 0 {
var rejectedHashes []string
// updateRejectedOrders
for _, r := range rejectedItems {
rejectedHashes = append(rejectedHashes, r.Hash.Hex())
if updatedTakerLendingItem.Hash == r.Hash && !txMatchTime.Before(r.UpdatedAt) {
// cache r history for handling reorg
historyRecord := lendingstate.LendingItemHistoryItem{
TxHash: updatedTakerLendingItem.TxHash,
FilledAmount: lendingstate.CloneBigInt(updatedTakerLendingItem.FilledAmount),
Status: updatedTakerLendingItem.Status,
UpdatedAt: updatedTakerLendingItem.UpdatedAt,
}
l.UpdateLendingItemCache(updatedTakerLendingItem.LendingToken, updatedTakerLendingItem.CollateralToken, updatedTakerLendingItem.Hash, txHash, historyRecord)
// if whole order is rejected, status = REJECTED
// otherwise, status = FILLED
if updatedTakerLendingItem.FilledAmount.Sign() > 0 {
updatedTakerLendingItem.Status = lendingstate.LendingStatusFilled
} else {
updatedTakerLendingItem.Status = lendingstate.LendingStatusReject
}
updatedTakerLendingItem.TxHash = txHash
updatedTakerLendingItem.UpdatedAt = txMatchTime
if err := db.PutObject(updatedTakerLendingItem.Hash, updatedTakerLendingItem); err != nil {
return fmt.Errorf("SDKNode: failed to reject takerOrder. Hash: %s Error: %s", updatedTakerLendingItem.Hash.Hex(), err.Error())
}
}
}
items := db.GetListItemByHashes(rejectedHashes, &lendingstate.LendingItem{})
if items != nil {
dirtyRejectedItems := items.([]*lendingstate.LendingItem)
for _, r := range dirtyRejectedItems {
if txMatchTime.Before(r.UpdatedAt) {
log.Debug("Ignore old orders/trades reject", "txHash", txHash.Hex(), "txTime", txMatchTime.UnixNano(), "updatedAt", updatedTakerLendingItem.UpdatedAt.UnixNano())
continue
}
// cache lendingItem for handling reorg
historyRecord := lendingstate.LendingItemHistoryItem{
TxHash: r.TxHash,
FilledAmount: lendingstate.CloneBigInt(r.FilledAmount),
Status: r.Status,
UpdatedAt: r.UpdatedAt,
}
l.UpdateLendingItemCache(r.LendingToken, r.CollateralToken, r.Hash, txHash, historyRecord)
dirtyFilledAmount, ok := makerDirtyFilledAmount[r.Hash.Hex()]
if ok && dirtyFilledAmount != nil {
r.FilledAmount = new(big.Int).Add(r.FilledAmount, dirtyFilledAmount)
}
// if whole order is rejected, status = REJECTED
// otherwise, status = FILLED
if r.FilledAmount.Sign() > 0 {
r.Status = lendingstate.LendingStatusFilled
} else {
r.Status = lendingstate.LendingStatusReject
}
r.TxHash = txHash
r.UpdatedAt = txMatchTime
if err = db.PutObject(r.Hash, r); err != nil {
return fmt.Errorf("SDKNode: failed to update rejectedOder to sdkNode %s", err.Error())
}
}
}
}
if err := db.CommitLendingBulk(); err != nil {
return fmt.Errorf("SDKNode fail to commit bulk update lendingItem/lendingTrades at txhash %s . Error: %s", txHash.Hex(), err.Error())
}
return nil
}
func (l *Lending) UpdateLiquidatedTrade(blockTime uint64, result lendingstate.FinalizedResult, trades map[common.Hash]*lendingstate.LendingTrade) error {
db := l.GetMongoDB()
db.InitLendingBulk()
txhash := result.TxHash
txTime := time.Unix(int64(blockTime), 0).UTC()
if err := l.UpdateLendingTrade(trades, txhash, txTime); err != nil {
return err
}
// adding auto repay transaction
if len(result.AutoRepay) > 0 {
for _, hash := range result.AutoRepay {
trade := trades[hash]
if trade == nil {
continue
}
paymentBalance := lendingstate.CalculateTotalRepayValue(blockTime, trade.LiquidationTime, trade.Term, trade.Interest, trade.Amount)
repayItem := &lendingstate.LendingItem{
Quantity: paymentBalance,
Interest: big.NewInt(int64(trade.Interest)),
Side: "",
Type: lendingstate.Repay,
LendingToken: trade.LendingToken,
CollateralToken: trade.CollateralToken,
FilledAmount: paymentBalance,
Status: lendingstate.Repay,
Relayer: trade.BorrowingRelayer,
Term: trade.Term,
UserAddress: trade.Borrower,
Signature: nil,
Hash: trade.Hash,
TxHash: txhash,
Nonce: nil,
CreatedAt: txTime,
UpdatedAt: txTime,
LendingId: 0,
LendingTradeId: trade.TradeId,
AutoTopUp: true, // auto repay
ExtraData: "",
}
if err := db.PutObject(repayItem.Hash, repayItem); err != nil {
return err
}
}
}
// adding auto topup transaction
if len(result.AutoTopUp) > 0 {
oldTradeHashes := []string{}
for _, hash := range result.AutoTopUp {
oldTradeHashes = append(oldTradeHashes, hash.Hex())
}
items := db.GetListItemByHashes(oldTradeHashes, &lendingstate.LendingTrade{})
if items != nil && len(items.([]*lendingstate.LendingTrade)) > 0 {
for _, oldTrade := range items.([]*lendingstate.LendingTrade) {
newTrade := trades[oldTrade.Hash]
topUpAmount := new(big.Int).Sub(newTrade.CollateralLockedAmount, oldTrade.CollateralLockedAmount)
extraData, _ := json.Marshal(struct {
Price *big.Int
}{
Price: new(big.Int).Div(new(big.Int).Mul(newTrade.LiquidationPrice, common.BaseTopUp), common.RateTopUp),
})
topUpItem := &lendingstate.LendingItem{
Quantity: topUpAmount,
Interest: big.NewInt(int64(oldTrade.Interest)),
Side: "",
Type: lendingstate.TopUp,
LendingToken: oldTrade.LendingToken,
CollateralToken: oldTrade.CollateralToken,
FilledAmount: topUpAmount,
Status: lendingstate.TopUp,
AutoTopUp: true, // auto topup
Relayer: oldTrade.BorrowingRelayer,
Term: oldTrade.Term,
UserAddress: oldTrade.Borrower,
Signature: nil,
Hash: oldTrade.Hash,
TxHash: txhash,
Nonce: nil,
CreatedAt: txTime,
UpdatedAt: txTime,
LendingId: 0,
LendingTradeId: oldTrade.TradeId,
ExtraData: string(extraData),
}
if err := db.PutObject(topUpItem.Hash, topUpItem); err != nil {
return err
}
}
}
}
// adding auto recall transaction
if len(result.AutoRecall) > 0 {
oldTradeHashes := []string{}
for _, hash := range result.AutoRecall {
oldTradeHashes = append(oldTradeHashes, hash.Hex())
}
items := db.GetListItemByHashes(oldTradeHashes, &lendingstate.LendingTrade{})
if items != nil && len(items.([]*lendingstate.LendingTrade)) > 0 {
for _, oldTrade := range items.([]*lendingstate.LendingTrade) {
newTrade := trades[oldTrade.Hash]
recallAmount := new(big.Int).Sub(oldTrade.CollateralLockedAmount, newTrade.CollateralLockedAmount)
extraData, _ := json.Marshal(struct {
Price *big.Int
}{
Price: new(big.Int).Div(new(big.Int).Mul(newTrade.LiquidationPrice, oldTrade.DepositRate), oldTrade.LiquidationRate),
})
topUpItem := &lendingstate.LendingItem{
Quantity: recallAmount,
Interest: big.NewInt(int64(oldTrade.Interest)),
Side: "",
Type: lendingstate.Recall,
LendingToken: oldTrade.LendingToken,
CollateralToken: oldTrade.CollateralToken,
FilledAmount: recallAmount,
Status: lendingstate.Recall,
AutoTopUp: true, // auto recall
Relayer: oldTrade.BorrowingRelayer,
Term: oldTrade.Term,
UserAddress: oldTrade.Borrower,
Signature: nil,
Hash: oldTrade.Hash,
TxHash: txhash,
Nonce: nil,
CreatedAt: txTime,
UpdatedAt: txTime,
LendingId: 0,
LendingTradeId: oldTrade.TradeId,
ExtraData: string(extraData),
}
if err := db.PutObject(topUpItem.Hash, topUpItem); err != nil {
return err
}
}
}
}
if err := db.CommitLendingBulk(); err != nil {
return fmt.Errorf("failed to updateLendingTrade . Err: %v", err)
}
return nil
}
func (l *Lending) UpdateLendingTrade(trades map[common.Hash]*lendingstate.LendingTrade, txhash common.Hash, txTime time.Time) error {
db := l.GetMongoDB()
hashQuery := []string{}
if len(trades) == 0 {
return nil
}
for _, trade := range trades {
hashQuery = append(hashQuery, trade.Hash.Hex())
}
items := db.GetListItemByHashes(hashQuery, &lendingstate.LendingTrade{})
if items != nil && len(items.([]*lendingstate.LendingTrade)) > 0 {
for _, trade := range items.([]*lendingstate.LendingTrade) {
history := lendingstate.LendingTradeHistoryItem{
TxHash: trade.TxHash,
CollateralLockedAmount: trade.CollateralLockedAmount,
LiquidationPrice: trade.LiquidationPrice,
Status: trade.Status,
UpdatedAt: trade.UpdatedAt,
}
l.UpdateLendingTradeCache(trade.Hash, txhash, history)
trade.TxHash = txhash
trade.UpdatedAt = txTime
newTrade := trades[trade.Hash]
trade.CollateralLockedAmount = newTrade.CollateralLockedAmount
trade.Status = newTrade.Status
trade.LiquidationPrice = newTrade.LiquidationPrice
trade.ExtraData = newTrade.ExtraData
if err := db.PutObject(trade.Hash, trade); err != nil {
return err
}
}
log.Debug("UpdateLendingTrade successfully", "txhash", txhash, "hash", hashQuery)
} else {
// not update, just upsert
for _, trade := range trades {
if err := db.PutObject(trade.Hash, trade); err != nil {
return err
}
}
}
return nil
}
func (l *Lending) GetLendingState(block *types.Block, author common.Address) (*lendingstate.LendingStateDB, error) {
root, err := l.GetLendingStateRoot(block, author)
if err != nil {
@ -690,86 +216,6 @@ func (l *Lending) UpdateLendingTradeCache(hash common.Hash, txhash common.Hash,
l.lendingTradeHistory.Add(txhash, lendingCacheAtTxHash)
}
func (l *Lending) RollbackLendingData(txhash common.Hash) error {
db := l.GetMongoDB()
db.InitLendingBulk()
// rollback lendingItem
items := db.GetListItemByTxHash(txhash, &lendingstate.LendingItem{})
if items != nil {
for _, item := range items.([]*lendingstate.LendingItem) {
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
}
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))
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
}
item.TxHash = lendingItemHistory.TxHash
item.Status = lendingItemHistory.Status
item.FilledAmount = lendingstate.CloneBigInt(lendingItemHistory.FilledAmount)
item.UpdatedAt = lendingItemHistory.UpdatedAt
log.Debug("XDCxlending reorg: update item to the last lendingItemHistory", "item", lendingstate.ToJSON(item), "lendingItemHistory", lendingItemHistory)
if err := db.PutObject(item.Hash, item); err != nil {
return fmt.Errorf("failed to update reorg LendingItem. Err: %v . Item: %s", err.Error(), lendingstate.ToJSON(item))
}
}
}
// rollback lendingTrade
items = db.GetListItemByTxHash(txhash, &lendingstate.LendingTrade{})
if items != nil {
for _, trade := range items.([]*lendingstate.LendingTrade) {
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
}
lendingTradeHistoryItem := cacheAtTxHash[trade.Hash]
if (lendingTradeHistoryItem == lendingstate.LendingTradeHistoryItem{}) {
log.Debug("XDCxlending reorg: remove trade due to empty 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
}
trade.TxHash = lendingTradeHistoryItem.TxHash
trade.Status = lendingTradeHistoryItem.Status
trade.CollateralLockedAmount = lendingstate.CloneBigInt(lendingTradeHistoryItem.CollateralLockedAmount)
trade.LiquidationPrice = lendingstate.CloneBigInt(lendingTradeHistoryItem.LiquidationPrice)
trade.UpdatedAt = lendingTradeHistoryItem.UpdatedAt
log.Debug("XDCxlending reorg: update trade to the last lendingTradeHistoryItem", "trade", lendingstate.ToJSON(trade), "lendingTradeHistoryItem", lendingTradeHistoryItem)
if err := db.PutObject(trade.Hash, trade); err != nil {
return fmt.Errorf("failed to update reorg LendingTrade. Err: %v . Trade: %s", err.Error(), lendingstate.ToJSON(trade))
}
}
}
// remove repay/topup/recall history
db.DeleteItemByTxHash(txhash, &lendingstate.LendingItem{Type: lendingstate.Repay})
db.DeleteItemByTxHash(txhash, &lendingstate.LendingItem{Type: lendingstate.TopUp})
db.DeleteItemByTxHash(txhash, &lendingstate.LendingItem{Type: lendingstate.Recall})
if err := db.CommitLendingBulk(); err != nil {
return fmt.Errorf("failed to RollbackLendingData. %v", err)
}
return nil
}
func (l *Lending) ProcessLiquidationData(header *types.Header, chain consensus.ChainContext, statedb *state.StateDB, tradingState *tradingstate.TradingStateDB, lendingState *lendingstate.LendingStateDB) (updatedTrades map[common.Hash]*lendingstate.LendingTrade, liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades []*lendingstate.LendingTrade, err error) {
time := new(big.Int).SetUint64(header.Time)
updatedTrades = map[common.Hash]*lendingstate.LendingTrade{} // sum of liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades

View file

@ -71,10 +71,6 @@ var (
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.EnablePersonal,
utils.XDCXEnabledFlag,
utils.XDCXDBEngineFlag,
utils.XDCXDBConnectionUrlFlag,
utils.XDCXDBReplicaSetNameFlag,
utils.XDCXDBNameFlag,
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,

View file

@ -845,18 +845,6 @@ var (
}
// XDCX settings
XDCXEnabledFlag = &cli.BoolFlag{
Name: "XDCx",
Usage: "Enable the XDCX protocol",
Category: flags.XdcxCategory,
}
XDCXDBEngineFlag = &cli.StringFlag{
Name: "XDCx-dbengine",
Aliases: []string{"XDCx.dbengine"},
Usage: "Database engine for XDCX (leveldb, mongodb)",
Value: "leveldb",
Category: flags.XdcxCategory,
}
XDCXDBNameFlag = &cli.StringFlag{
Name: "XDCx-dbName",
Aliases: []string{"XDCx.dbName"},
@ -864,19 +852,6 @@ var (
Value: "XDCdex",
Category: flags.XdcxCategory,
}
XDCXDBConnectionUrlFlag = &cli.StringFlag{
Name: "XDCx-dbConnectionUrl",
Aliases: []string{"XDCx.dbConnectionUrl"},
Usage: "ConnectionUrl to database if dbEngine is mongodb. Host:port. If there are multiple instances, separated by comma. Eg: localhost:27017,localhost:27018",
Value: "localhost:27017",
Category: flags.XdcxCategory,
}
XDCXDBReplicaSetNameFlag = &cli.StringFlag{
Name: "XDCx-dbReplicaSetName",
Aliases: []string{"XDCx.dbReplicaSetName"},
Usage: "ReplicaSetName if Master-Slave is setup",
Category: flags.XdcxCategory,
}
)
var (
@ -1475,24 +1450,11 @@ func SetXDCXConfig(ctx *cli.Context, cfg *XDCx.Config, XDCDataDir string) {
// XDCx datadir: XDCDataDir/XDCx
cfg.DataDir = filepath.Join(XDCDataDir, "XDCx")
log.Info("XDCX datadir", "path", cfg.DataDir)
if ctx.IsSet(XDCXDBEngineFlag.Name) {
cfg.DBEngine = ctx.String(XDCXDBEngineFlag.Name)
} else {
cfg.DBEngine = XDCXDBEngineFlag.Value
}
if ctx.IsSet(XDCXDBNameFlag.Name) {
cfg.DBName = ctx.String(XDCXDBNameFlag.Name)
} else {
cfg.DBName = XDCXDBNameFlag.Value
}
if ctx.IsSet(XDCXDBConnectionUrlFlag.Name) {
cfg.ConnectionUrl = ctx.String(XDCXDBConnectionUrlFlag.Name)
} else {
cfg.ConnectionUrl = XDCXDBConnectionUrlFlag.Value
}
if ctx.IsSet(XDCXDBReplicaSetNameFlag.Name) {
cfg.ReplicaSetName = ctx.String(XDCXDBReplicaSetNameFlag.Name)
}
}
// SetEthConfig applies eth-related command line flags to the config.

View file

@ -2,7 +2,6 @@ package utils
import (
"math/big"
"time"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
@ -29,9 +28,6 @@ type TradingService interface {
GetTriegc() *prque.Prque[int64, common.Hash]
ApplyOrder(header *types.Header, coinbase common.Address, chain consensus.ChainContext, statedb *state.StateDB, XDCXstatedb *tradingstate.TradingStateDB, orderBook common.Hash, order *tradingstate.OrderItem) ([]map[string]string, []*tradingstate.OrderItem, error)
UpdateMediumPriceBeforeEpoch(epochNumber uint64, tradingStateDB *tradingstate.TradingStateDB, statedb *state.StateDB) error
IsSDKNode() bool
SyncDataToSDKNode(takerOrder *tradingstate.OrderItem, txHash common.Hash, txMatchTime time.Time, statedb *state.StateDB, trades []map[string]string, rejectedOrders []*tradingstate.OrderItem, dirtyOrderCount *uint64) error
RollbackReorgTxMatch(txhash common.Hash) error
GetTokenDecimal(chain consensus.ChainContext, statedb *state.StateDB, tokenAddr common.Address) (*big.Int, error)
}
@ -45,9 +41,6 @@ type LendingService interface {
GetCollateralPrices(header *types.Header, chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, collateralToken common.Address, lendingToken common.Address) (*big.Int, *big.Int, error)
GetMediumTradePriceBeforeEpoch(chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, baseToken common.Address, quoteToken common.Address) (*big.Int, error)
ProcessLiquidationData(header *types.Header, chain consensus.ChainContext, statedb *state.StateDB, tradingState *tradingstate.TradingStateDB, lendingState *lendingstate.LendingStateDB) (updatedTrades map[common.Hash]*lendingstate.LendingTrade, liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades []*lendingstate.LendingTrade, err error)
SyncDataToSDKNode(chain consensus.ChainContext, state *state.StateDB, block *types.Block, takerOrderInTx *lendingstate.LendingItem, txHash common.Hash, txMatchTime time.Time, trades []*lendingstate.LendingTrade, rejectedOrders []*lendingstate.LendingItem, dirtyOrderCount *uint64) error
UpdateLiquidatedTrade(blockTime uint64, result lendingstate.FinalizedResult, trades map[common.Hash]*lendingstate.LendingTrade) error
RollbackLendingData(txhash common.Hash) error
}
type PublicApiSnapshot struct {

View file

@ -138,9 +138,6 @@ func (v *BlockValidator) ValidateTradingOrder(statedb *state.StateDB, XDCxStated
Rejects: newRejectedOrders,
}
}
if XDCXService.IsSDKNode() {
v.bc.AddMatchingResult(txMatchBatch.TxHash, tradingResult)
}
return nil
}
@ -173,9 +170,6 @@ func (v *BlockValidator) ValidateLendingOrder(statedb *state.StateDB, lendingSta
Rejects: newRejectedOrders,
}
}
if XDCXService.IsSDKNode() {
v.bc.AddLendingResult(batch.TxHash, lendingResult)
}
return nil
}

View file

@ -1824,10 +1824,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []
// Only count canonical blocks for GC processing time
bc.gcproc += res.procTime
bc.UpdateBlocksHashCache(block)
if bc.chainConfig.IsTIPXDCX(block.Number()) && bc.chainConfig.XDPoS != nil && block.NumberU64() > bc.chainConfig.XDPoS.Epoch {
bc.logExchangeData(block)
bc.logLendingData(block)
}
case SideStatTy:
log.Debug("Inserted forked block from downloader", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed",
common.PrettyDuration(time.Since(start)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()))
@ -2282,10 +2278,6 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
// Only count canonical blocks for GC processing time
bc.gcproc += result.proctime
bc.UpdateBlocksHashCache(block)
if bc.chainConfig.IsTIPXDCXReceiver(block.Number()) && bc.chainConfig.XDPoS != nil && block.NumberU64() > bc.chainConfig.XDPoS.Epoch {
bc.logExchangeData(block)
bc.logLendingData(block)
}
case SideStatTy:
log.Debug("Inserted forked block from fetcher", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(), "elapsed",
common.PrettyDuration(time.Since(block.ReceivedAt)), "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()))
@ -2830,146 +2822,6 @@ func (bc *BlockChain) UpdateM1() error {
return nil
}
func (bc *BlockChain) logExchangeData(block *types.Block) {
engine, ok := bc.Engine().(*XDPoS.XDPoS)
if !ok || engine == nil {
return
}
XDCXService := engine.GetXDCXService()
if XDCXService == nil || !XDCXService.IsSDKNode() {
return
}
txMatchBatchData, err := ExtractTradingTransactions(block.Transactions())
if err != nil {
log.Error("failed to extract matching transaction", "err", err)
return
}
if len(txMatchBatchData) == 0 {
return
}
currentState, err := bc.State()
if err != nil {
log.Crit("logExchangeData: failed to get current state", "err", err)
return
}
start := time.Now()
defer func() {
//The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns
// That's why we should put this log statement in an anonymous function
log.Debug("logExchangeData takes", "time", common.PrettyDuration(time.Since(start)), "blockNumber", block.NumberU64())
}()
for _, txMatchBatch := range txMatchBatchData {
dirtyOrderCount := uint64(0)
for _, txMatch := range txMatchBatch.Data {
var (
takerOrderInTx *tradingstate.OrderItem
trades []map[string]string
rejectedOrders []*tradingstate.OrderItem
)
if takerOrderInTx, err = txMatch.DecodeOrder(); err != nil {
log.Error("SDK node decode takerOrderInTx failed", "txDataMatch", txMatch)
return
}
cacheKey := crypto.Keccak256Hash(txMatchBatch.TxHash.Bytes(), tradingstate.GetMatchingResultCacheKey(takerOrderInTx).Bytes())
// getTrades from cache
resultTrades, ok := bc.resultTrade.Get(cacheKey)
if ok && resultTrades != nil {
trades = resultTrades.([]map[string]string)
}
// getRejectedOrder from cache
rejected, ok := bc.rejectedOrders.Get(cacheKey)
if ok && rejected != nil {
rejectedOrders = rejected.([]*tradingstate.OrderItem)
}
txMatchTime := time.Unix(int64(block.Header().Time), 0).UTC()
if err := XDCXService.SyncDataToSDKNode(takerOrderInTx, txMatchBatch.TxHash, txMatchTime, currentState, trades, rejectedOrders, &dirtyOrderCount); err != nil {
log.Error("failed to SyncDataToSDKNode ", "blockNumber", block.Number(), "err", err)
return
}
}
}
}
func (bc *BlockChain) logLendingData(block *types.Block) {
engine, ok := bc.Engine().(*XDPoS.XDPoS)
if !ok || engine == nil {
return
}
XDCXService := engine.GetXDCXService()
if XDCXService == nil || !XDCXService.IsSDKNode() {
return
}
lendingService := engine.GetLendingService()
if lendingService == nil {
return
}
batches, err := ExtractLendingTransactions(block.Transactions())
if err != nil {
log.Error("failed to extract lending transaction", "err", err)
return
}
start := time.Now()
defer func() {
//The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns
// That's why we should put this log statement in an anonymous function
log.Debug("logLendingData takes", "time", common.PrettyDuration(time.Since(start)), "blockNumber", block.NumberU64())
}()
for _, batch := range batches {
dirtyOrderCount := uint64(0)
for _, item := range batch.Data {
var (
trades []*lendingstate.LendingTrade
rejectedOrders []*lendingstate.LendingItem
)
// getTrades from cache
resultLendingTrades, ok := bc.resultLendingTrade.Get(crypto.Keccak256Hash(batch.TxHash.Bytes(), lendingstate.GetLendingCacheKey(item).Bytes()))
if ok && resultLendingTrades != nil {
trades = resultLendingTrades.([]*lendingstate.LendingTrade)
}
// getRejectedOrder from cache
rejected, ok := bc.rejectedLendingItem.Get(crypto.Keccak256Hash(batch.TxHash.Bytes(), lendingstate.GetLendingCacheKey(item).Bytes()))
if ok && rejected != nil {
rejectedOrders = rejected.([]*lendingstate.LendingItem)
}
txMatchTime := time.Unix(int64(block.Header().Time), 0).UTC()
statedb, _ := bc.State()
if err := lendingService.SyncDataToSDKNode(bc, statedb.Copy(), block, item, batch.TxHash, txMatchTime, trades, rejectedOrders, &dirtyOrderCount); err != nil {
log.Error("lending: failed to SyncDataToSDKNode ", "blockNumber", block.Number(), "err", err)
return
}
}
}
// update finalizedTrades
if block.Number().Uint64()%bc.chainConfig.XDPoS.Epoch == common.LiquidateLendingTradeBlock {
finalizedTx, err := ExtractLendingFinalizedTradeTransactions(block.Transactions())
if err != nil {
log.Error("failed to extract finalizedTrades transaction", "err", err)
return
}
finalizedTrades := map[common.Hash]*lendingstate.LendingTrade{}
finalizedData, ok := bc.finalizedTrade.Get(finalizedTx.TxHash)
if ok && finalizedData != nil {
finalizedTrades = finalizedData.(map[common.Hash]*lendingstate.LendingTrade)
}
if len(finalizedTrades) > 0 {
if err := lendingService.UpdateLiquidatedTrade(block.Time(), finalizedTx, finalizedTrades); err != nil {
log.Error("lending: failed to UpdateLiquidatedTrade ", "blockNumber", block.Number(), "err", err)
return
}
}
}
}
func (bc *BlockChain) AddMatchingResult(txHash common.Hash, matchingResults map[common.Hash]tradingstate.MatchingResult) {
for hash, result := range matchingResults {
cacheKey := crypto.Keccak256Hash(txHash.Bytes(), hash.Bytes())
@ -3078,17 +2930,10 @@ func (bc *BlockChain) processTradingAndLendingStates(isValidBlockNumber bool, bl
}
// liquidate / finalize open lendingTrades
if block.Number().Uint64()%bc.chainConfig.XDPoS.Epoch == common.LiquidateLendingTradeBlock {
finalizedTrades, _, _, _, _, err := lendingService.ProcessLiquidationData(block.Header(), bc, statedb, tradingState, lendingState)
_, _, _, _, _, err := lendingService.ProcessLiquidationData(block.Header(), bc, statedb, tradingState, lendingState)
if err != nil {
return tradingState, lendingState, fmt.Errorf("failed to ProcessLiquidationData. Err: %v", err)
}
if tradingService.IsSDKNode() {
finalizedTx, err := ExtractLendingFinalizedTradeTransactions(block.Transactions())
if err != nil {
return tradingState, lendingState, err
}
bc.AddFinalizedTrades(finalizedTx.TxHash, finalizedTrades)
}
}
}

View file

@ -752,15 +752,11 @@ func (w *worker) commitNewWork() {
var (
txs *types.TransactionsByPriceAndNonce
specialTxs types.Transactions
tradingTransaction *types.Transaction
lendingTransaction *types.Transaction
tradingTxMatches []tradingstate.TxDataMatch
tradingMatchingResults map[common.Hash]tradingstate.MatchingResult
lendingMatchingResults map[common.Hash]lendingstate.MatchingResult
lendingInput []*lendingstate.LendingItem
updatedTrades map[common.Hash]*lendingstate.LendingTrade
liquidatedTrades, autoRepayTrades, autoTopUpTrades, autoRecallTrades []*lendingstate.LendingTrade
lendingFinalizedTradeTransaction *types.Transaction
)
feeCapacity := state.GetTRC21FeeCapacityFromStateWithCache(parent.Root(), work.state)
if w.config.XDPoS != nil {
@ -800,7 +796,7 @@ func (w *worker) commitNewWork() {
log.Debug("Start processing order pending")
tradingOrderPending, _ := w.eth.OrderPool().Pending()
log.Debug("Start processing order pending", "len", len(tradingOrderPending))
tradingTxMatches, tradingMatchingResults = XDCX.ProcessOrderPending(header, w.coinbase, w.chain, tradingOrderPending, work.state, work.tradingState)
tradingTxMatches, _ = XDCX.ProcessOrderPending(header, w.coinbase, w.chain, tradingOrderPending, work.state, work.tradingState)
log.Debug("trading transaction matches found", "tradingTxMatches", len(tradingTxMatches))
lendingOrderPending, _ := w.eth.LendingPool().Pending()
@ -832,15 +828,10 @@ func (w *worker) commitNewWork() {
if err != nil {
log.Error("Fail to create tx matches", "error", err)
return
} else {
tradingTransaction = txM
if XDCX.IsSDKNode() {
w.chain.AddMatchingResult(tradingTransaction.Hash(), tradingMatchingResults)
}
// force adding trading, lending transaction to this block
if tradingTransaction != nil {
specialTxs = append(specialTxs, tradingTransaction)
}
}
// force adding trading, lending transaction to this block
if txM != nil {
specialTxs = append(specialTxs, txM)
}
}
@ -862,14 +853,9 @@ func (w *worker) commitNewWork() {
if err != nil {
log.Error("Fail to create lending tx", "error", err)
return
} else {
lendingTransaction = signedLendingTx
if XDCX.IsSDKNode() {
w.chain.AddLendingResult(lendingTransaction.Hash(), lendingMatchingResults)
}
if lendingTransaction != nil {
specialTxs = append(specialTxs, lendingTransaction)
}
}
if signedLendingTx != nil {
specialTxs = append(specialTxs, signedLendingTx)
}
}
@ -886,14 +872,9 @@ func (w *worker) commitNewWork() {
if err != nil {
log.Error("Fail to create lending tx", "error", err)
return
} else {
lendingFinalizedTradeTransaction = signedFinalizedTx
if XDCX.IsSDKNode() {
w.chain.AddFinalizedTrades(lendingFinalizedTradeTransaction.Hash(), updatedTrades)
}
if lendingFinalizedTradeTransaction != nil {
specialTxs = append(specialTxs, lendingFinalizedTradeTransaction)
}
}
if signedFinalizedTx != nil {
specialTxs = append(specialTxs, signedFinalizedTx)
}
}
}