rebase from dev-upgrade

This commit is contained in:
Liam Lai 2024-06-19 16:05:08 +08:00
commit d28c7f659d
213 changed files with 10650 additions and 2919 deletions

View file

@ -292,10 +292,10 @@ func (XDCx *XDCX) GetAveragePriceLastEpoch(chain consensus.ChainContext, statedb
// return tokenQuantity (after convert from XDC to token), tokenPriceInXDC, error
func (XDCx *XDCX) ConvertXDCToToken(chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, token common.Address, quantity *big.Int) (*big.Int, *big.Int, error) {
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
return quantity, common.BasePrice, nil
}
tokenPriceInXDC, err := XDCx.GetAveragePriceLastEpoch(chain, statedb, tradingStateDb, token, common.HexToAddress(common.XDCNativeAddress))
tokenPriceInXDC, err := XDCx.GetAveragePriceLastEpoch(chain, statedb, tradingStateDb, token, common.XDCNativeAddressBinary)
if err != nil || tokenPriceInXDC == nil || tokenPriceInXDC.Sign() <= 0 {
return common.Big0, common.Big0, err
}
@ -595,10 +595,11 @@ func (XDCx *XDCX) GetTriegc() *prque.Prque {
func (XDCx *XDCX) GetTradingStateRoot(block *types.Block, author common.Address) (common.Hash, error) {
for _, tx := range block.Transactions() {
from := *(tx.From())
if tx.To() != nil && tx.To().Hex() == common.TradingStateAddr && from.String() == author.String() {
if len(tx.Data()) >= 32 {
return common.BytesToHash(tx.Data()[:32]), nil
to := tx.To()
if to != nil && *to == common.TradingStateAddrBinary && *tx.From() == author {
data := tx.Data()
if len(data) >= 32 {
return common.BytesToHash(data[:32]), nil
}
}
}

View file

@ -236,11 +236,11 @@ func (XDCx *XDCX) processOrderList(coinbase common.Address, chain consensus.Chai
maxTradedQuantity = tradingstate.CloneBigInt(amount)
}
var quotePrice *big.Int
if oldestOrder.QuoteToken.String() != common.XDCNativeAddress {
quotePrice = tradingStateDB.GetLastPrice(tradingstate.GetTradingOrderBookHash(oldestOrder.QuoteToken, common.HexToAddress(common.XDCNativeAddress)))
if oldestOrder.QuoteToken != common.XDCNativeAddressBinary {
quotePrice = tradingStateDB.GetLastPrice(tradingstate.GetTradingOrderBookHash(oldestOrder.QuoteToken, common.XDCNativeAddressBinary))
log.Debug("TryGet quotePrice QuoteToken/XDC", "quotePrice", quotePrice)
if quotePrice == nil || quotePrice.Sign() == 0 {
inversePrice := tradingStateDB.GetLastPrice(tradingstate.GetTradingOrderBookHash(common.HexToAddress(common.XDCNativeAddress), oldestOrder.QuoteToken))
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)
@ -374,10 +374,10 @@ func (XDCx *XDCX) getTradeQuantity(quotePrice *big.Int, coinbase common.Address,
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)
}
if makerOrder.QuoteToken.String() == common.XDCNativeAddress {
if makerOrder.QuoteToken == common.XDCNativeAddressBinary {
quotePrice = quoteTokenDecimal
}
if takerOrder.ExchangeAddress.String() == makerOrder.ExchangeAddress.String() {
if takerOrder.ExchangeAddress == makerOrder.ExchangeAddress {
if err := tradingstate.CheckRelayerFee(takerOrder.ExchangeAddress, new(big.Int).Mul(common.RelayerFee, big.NewInt(2)), statedb); err != nil {
log.Debug("Reject order Taker Exchnage = Maker Exchange , relayer not enough fee ", "err", err)
return tradingstate.Zero, false, nil, nil

View file

@ -1,12 +1,13 @@
package XDCx
import (
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
)
func Test_getCancelFeeV1(t *testing.T) {
@ -103,9 +104,9 @@ func Test_getCancelFee(t *testing.T) {
XDCx.SetTokenDecimal(testTokenB, tokenBDecimal)
// set tokenAPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenA, common.HexToAddress(common.XDCNativeAddress)), common.BasePrice)
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenA, common.XDCNativeAddressBinary), common.BasePrice)
// set tokenBPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.HexToAddress(common.XDCNativeAddress), testTokenB), tokenBDecimal)
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.XDCNativeAddressBinary, testTokenB), tokenBDecimal)
type CancelFeeArg struct {
feeRate *big.Int
@ -127,7 +128,7 @@ func Test_getCancelFee(t *testing.T) {
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenA,
QuoteToken: common.HexToAddress(common.XDCNativeAddress),
QuoteToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
},
@ -142,7 +143,7 @@ func Test_getCancelFee(t *testing.T) {
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: testTokenA,
QuoteToken: common.HexToAddress(common.XDCNativeAddress),
QuoteToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Bid,
},
@ -156,7 +157,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
@ -172,7 +173,7 @@ func Test_getCancelFee(t *testing.T) {
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Side: tradingstate.Bid,
},
@ -188,7 +189,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
@ -203,7 +204,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
feeRate: common.Big0,
order: &tradingstate.OrderItem{
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Bid,
@ -218,7 +219,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: tradingstate.Ask,
@ -234,7 +235,7 @@ func Test_getCancelFee(t *testing.T) {
feeRate: new(big.Int).SetUint64(10), // 10/10000= 0.1%
order: &tradingstate.OrderItem{
Quantity: new(big.Int).SetUint64(10000),
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: testTokenA,
Side: tradingstate.Bid,
},

View file

@ -48,7 +48,7 @@ func (XDCx *XDCX) GetTokenDecimal(chain consensus.ChainContext, statedb *state.S
if tokenDecimal, ok := XDCx.tokenDecimalCache.Get(tokenAddr); ok {
return tokenDecimal.(*big.Int), nil
}
if tokenAddr.String() == common.XDCNativeAddress {
if tokenAddr == common.XDCNativeAddressBinary {
XDCx.tokenDecimalCache.Add(tokenAddr, common.BasePrice)
return common.BasePrice, nil
}

View file

@ -239,7 +239,7 @@ func (o *OrderItem) verifyRelayer(state *state.StateDB) error {
return nil
}
//verify signatures
// verify signatures
func (o *OrderItem) verifySignature() error {
bigstr := o.Nonce.String()
n, err := strconv.ParseInt(bigstr, 10, 64)
@ -269,7 +269,7 @@ func (o *OrderItem) verifyOrderType() error {
return nil
}
//verify order side
// verify order side
func (o *OrderItem) verifyOrderSide() error {
if o.Side != Bid && o.Side != Ask {
@ -356,11 +356,11 @@ func VerifyPair(statedb *state.StateDB, exchangeAddress, baseToken, quoteToken c
func VerifyBalance(statedb *state.StateDB, XDCxStateDb *TradingStateDB, order *types.OrderTransaction, baseDecimal, quoteDecimal *big.Int) error {
var quotePrice *big.Int
if order.QuoteToken().String() != common.XDCNativeAddress {
quotePrice = XDCxStateDb.GetLastPrice(GetTradingOrderBookHash(order.QuoteToken(), common.HexToAddress(common.XDCNativeAddress)))
if order.QuoteToken() != common.XDCNativeAddressBinary {
quotePrice = XDCxStateDb.GetLastPrice(GetTradingOrderBookHash(order.QuoteToken(), common.XDCNativeAddressBinary))
log.Debug("TryGet quotePrice QuoteToken/XDC", "quotePrice", quotePrice)
if quotePrice == nil || quotePrice.Sign() == 0 {
inversePrice := XDCxStateDb.GetLastPrice(GetTradingOrderBookHash(common.HexToAddress(common.XDCNativeAddress), order.QuoteToken()))
inversePrice := XDCxStateDb.GetLastPrice(GetTradingOrderBookHash(common.XDCNativeAddressBinary, order.QuoteToken()))
log.Debug("TryGet inversePrice XDC/QuoteToken", "inversePrice", inversePrice)
if inversePrice != nil && inversePrice.Sign() > 0 {
quotePrice = new(big.Int).Mul(common.BasePrice, quoteDecimal)

View file

@ -159,9 +159,9 @@ func CheckRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateD
}
func AddTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
balance := statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD TOKEN XDC NATIVE BEFORE", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD TOKEN XDC NATIVE BEFORE", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
statedb.AddBalance(addr, value)
balance = statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD XDC NATIVE BALANCE AFTER", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
@ -186,10 +186,9 @@ func AddTokenBalance(addr common.Address, value *big.Int, token common.Address,
func SubTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
balance := statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE BEFORE", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE BEFORE", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
if balance.Cmp(value) < 0 {
return errors.Errorf("value %s in token %s not enough , have : %s , want : %s ", addr.String(), token.String(), balance, value)
}
@ -219,7 +218,7 @@ func SubTokenBalance(addr common.Address, value *big.Int, token common.Address,
func CheckSubTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB, mapBalances map[common.Address]map[common.Address]*big.Int) (*big.Int, error) {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
var balance *big.Int
if value := mapBalances[token][addr]; value != nil {
balance = value
@ -256,7 +255,7 @@ func CheckSubTokenBalance(addr common.Address, value *big.Int, token common.Addr
func CheckAddTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB, mapBalances map[common.Address]map[common.Address]*big.Int) (*big.Int, error) {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
var balance *big.Int
if value := mapBalances[token][addr]; value != nil {
balance = value
@ -308,7 +307,7 @@ func CheckSubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.Sta
func GetTokenBalance(addr common.Address, token common.Address, statedb *state.StateDB) *big.Int {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
return statedb.GetBalance(addr)
}
// TRC tokens
@ -323,7 +322,7 @@ func GetTokenBalance(addr common.Address, token common.Address, statedb *state.S
func SetTokenBalance(addr common.Address, balance *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
statedb.SetBalance(addr, balance)
return nil
}

View file

@ -52,7 +52,7 @@ func GetSettleBalance(quotePrice *big.Int, takerSide string, takerFeeRate *big.I
log.Debug("quantity trade too small", "quoteTokenQuantity", quoteTokenQuantity, "makerFee", makerFee, "defaultFee", defaultFee)
return result, ErrQuantityTradeTooSmall
}
if quoteToken.String() != common.XDCNativeAddress && quotePrice != nil && quotePrice.Cmp(common.Big0) > 0 {
if quoteToken != common.XDCNativeAddressBinary && quotePrice != nil && quotePrice.Cmp(common.Big0) > 0 {
// defaultFeeInXDC
defaultFeeInXDC := new(big.Int).Mul(defaultFee, quotePrice)
defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, quoteTokenDecimal)
@ -69,7 +69,7 @@ func GetSettleBalance(quotePrice *big.Int, takerSide string, takerFeeRate *big.I
log.Debug("takerFee too small", "quoteTokenQuantity", quoteTokenQuantity, "takerFee", takerFee, "exTakerReceivedFee", exTakerReceivedFee, "quotePrice", quotePrice, "defaultFeeInXDC", defaultFeeInXDC)
return result, ErrQuantityTradeTooSmall
}
} else if quoteToken.String() == common.XDCNativeAddress {
} else if quoteToken == common.XDCNativeAddressBinary {
exMakerReceivedFee := makerFee
if (exMakerReceivedFee.Cmp(common.RelayerFee) <= 0 && exMakerReceivedFee.Sign() > 0) || defaultFee.Cmp(common.RelayerFee) <= 0 {
log.Debug("makerFee too small", "quantityToTrade", quantityToTrade, "makerFee", makerFee, "exMakerReceivedFee", exMakerReceivedFee, "makerFeeRate", makerFeeRate, "defaultFee", defaultFee)
@ -108,7 +108,7 @@ func GetSettleBalance(quotePrice *big.Int, takerSide string, takerFeeRate *big.I
log.Debug("quantity trade too small", "quoteTokenQuantity", quoteTokenQuantity, "takerFee", takerFee)
return result, ErrQuantityTradeTooSmall
}
if quoteToken.String() != common.XDCNativeAddress && quotePrice != nil && quotePrice.Cmp(common.Big0) > 0 {
if quoteToken != common.XDCNativeAddressBinary && quotePrice != nil && quotePrice.Cmp(common.Big0) > 0 {
// defaultFeeInXDC
defaultFeeInXDC := new(big.Int).Mul(defaultFee, quotePrice)
defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, quoteTokenDecimal)
@ -126,7 +126,7 @@ func GetSettleBalance(quotePrice *big.Int, takerSide string, takerFeeRate *big.I
log.Debug("takerFee too small", "quoteTokenQuantity", quoteTokenQuantity, "takerFee", takerFee, "exTakerReceivedFee", exTakerReceivedFee, "quotePrice", quotePrice, "defaultFeeInXDC", defaultFeeInXDC)
return result, ErrQuantityTradeTooSmall
}
} else if quoteToken.String() == common.XDCNativeAddress {
} else if quoteToken == common.XDCNativeAddressBinary {
exMakerReceivedFee := makerFee
if (exMakerReceivedFee.Cmp(common.RelayerFee) <= 0 && exMakerReceivedFee.Sign() > 0) || defaultFee.Cmp(common.RelayerFee) <= 0 {
log.Debug("makerFee too small", "quantityToTrade", quantityToTrade, "makerFee", makerFee, "exMakerReceivedFee", exMakerReceivedFee, "makerFeeRate", makerFeeRate, "defaultFee", defaultFee)

View file

@ -1,10 +1,11 @@
package tradingstate
import (
"github.com/XinFinOrg/XDPoSChain/common"
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
)
func TestGetSettleBalance(t *testing.T) {
@ -89,7 +90,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Bid,
takerFeeRate: big.NewInt(10), // feeRate 0.1%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -106,7 +107,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Bid,
takerFeeRate: big.NewInt(5), // feeRate 0.05%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -124,7 +125,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Bid,
takerFeeRate: big.NewInt(10), // feeRate 0.1%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -132,8 +133,8 @@ func TestGetSettleBalance(t *testing.T) {
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
&SettleBalance{
Taker: TradeResult{Fee: testFee, InToken: testToken, InTotal: tradeQuantity, OutToken: common.HexToAddress(common.XDCNativeAddress), OutTotal: tradeQuantityIncludedFee},
Maker: TradeResult{Fee: testFee, InToken: common.HexToAddress(common.XDCNativeAddress), InTotal: tradeQuantityExcludedFee, OutToken: testToken, OutTotal: tradeQuantity},
Taker: TradeResult{Fee: testFee, InToken: testToken, InTotal: tradeQuantity, OutToken: common.XDCNativeAddressBinary, OutTotal: tradeQuantityIncludedFee},
Maker: TradeResult{Fee: testFee, InToken: common.XDCNativeAddressBinary, InTotal: tradeQuantityExcludedFee, OutToken: testToken, OutTotal: tradeQuantity},
},
false,
},
@ -196,7 +197,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Ask,
takerFeeRate: big.NewInt(10), // feeRate 0.1%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -213,7 +214,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Ask,
takerFeeRate: big.NewInt(5), // feeRate 0.05%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -231,7 +232,7 @@ func TestGetSettleBalance(t *testing.T) {
takerSide: Ask,
takerFeeRate: big.NewInt(10), // feeRate 15%
baseToken: testToken,
quoteToken: common.HexToAddress(common.XDCNativeAddress),
quoteToken: common.XDCNativeAddressBinary,
makerPrice: common.BasePrice,
makerFeeRate: big.NewInt(10), // feeRate 0.1%
baseTokenDecimal: common.BasePrice,
@ -239,8 +240,8 @@ func TestGetSettleBalance(t *testing.T) {
quantityToTrade: new(big.Int).Mul(big.NewInt(1000), common.BasePrice),
},
&SettleBalance{
Maker: TradeResult{Fee: testFee, InToken: testToken, InTotal: tradeQuantity, OutToken: common.HexToAddress(common.XDCNativeAddress), OutTotal: tradeQuantityIncludedFee},
Taker: TradeResult{Fee: testFee, InToken: common.HexToAddress(common.XDCNativeAddress), InTotal: tradeQuantityExcludedFee, OutToken: testToken, OutTotal: tradeQuantity},
Maker: TradeResult{Fee: testFee, InToken: testToken, InTotal: tradeQuantity, OutToken: common.XDCNativeAddressBinary, OutTotal: tradeQuantityIncludedFee},
Taker: TradeResult{Fee: testFee, InToken: common.XDCNativeAddressBinary, InTotal: tradeQuantityExcludedFee, OutToken: testToken, OutTotal: tradeQuantity},
},
false,
},

View file

@ -696,10 +696,11 @@ func (l *Lending) GetTriegc() *prque.Prque {
func (l *Lending) GetLendingStateRoot(block *types.Block, author common.Address) (common.Hash, error) {
for _, tx := range block.Transactions() {
from := *(tx.From())
if tx.To() != nil && tx.To().Hex() == common.TradingStateAddr && from.String() == author.String() {
if len(tx.Data()) >= 64 {
return common.BytesToHash(tx.Data()[32:]), nil
to := tx.To()
if to != nil && *to == common.TradingStateAddrBinary && *tx.From() == author {
data := tx.Data()
if len(data) >= 64 {
return common.BytesToHash(data[32:]), nil
}
}
}

View file

@ -1,7 +1,7 @@
package lendingstate
import (
"fmt"
"errors"
"math/big"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
@ -273,10 +273,10 @@ func GetAllLendingBooks(statedb *state.StateDB) (mapLendingBook map[common.Hash]
baseTokens := GetSupportedBaseToken(statedb)
terms := GetSupportedTerms(statedb)
if len(baseTokens) == 0 {
return nil, fmt.Errorf("GetAllLendingBooks: empty baseToken list")
return nil, errors.New("GetAllLendingBooks: empty baseToken list")
}
if len(terms) == 0 {
return nil, fmt.Errorf("GetAllLendingPairs: empty term list")
return nil, errors.New("GetAllLendingPairs: empty term list")
}
for _, baseToken := range baseTokens {
for _, term := range terms {
@ -295,10 +295,10 @@ func GetAllLendingPairs(statedb *state.StateDB) (allPairs []LendingPair, err err
baseTokens := GetSupportedBaseToken(statedb)
collaterals := GetAllCollateral(statedb)
if len(baseTokens) == 0 {
return allPairs, fmt.Errorf("GetAllLendingPairs: empty baseToken list")
return allPairs, errors.New("GetAllLendingPairs: empty baseToken list")
}
if len(collaterals) == 0 {
return allPairs, fmt.Errorf("GetAllLendingPairs: empty collateral list")
return allPairs, errors.New("GetAllLendingPairs: empty collateral list")
}
for _, baseToken := range baseTokens {
for _, collateral := range collaterals {

View file

@ -1,6 +1,7 @@
package lendingstate
import (
"errors"
"fmt"
"math/big"
"strconv"
@ -260,7 +261,7 @@ func (l *LendingItem) VerifyCollateral(state *state.StateDB) error {
validCollateral := false
collateralList := GetCollaterals(state, l.Relayer, l.LendingToken, l.Term)
for _, collateral := range collateralList {
if l.CollateralToken.String() == collateral.String() {
if l.CollateralToken == collateral {
validCollateral = true
break
}
@ -359,7 +360,7 @@ func (l *LendingItem) VerifyLendingSignature() error {
tx.ImportSignature(V, R, S)
from, _ := types.LendingSender(types.LendingTxSigner{}, tx)
if from != tx.UserAddress() {
return fmt.Errorf("verify lending item: invalid signature")
return errors.New("verify lending item: invalid signature")
}
return nil
}
@ -411,7 +412,7 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
defaultFee := new(big.Int).Mul(quantity, new(big.Int).SetUint64(DefaultFeeRate))
defaultFee = new(big.Int).Div(defaultFee, common.XDCXBaseFee)
defaultFeeInXDC := common.Big0
if lendingToken.String() != common.XDCNativeAddress {
if lendingToken != common.XDCNativeAddressBinary {
defaultFeeInXDC = new(big.Int).Mul(defaultFee, lendTokenXDCPrice)
defaultFeeInXDC = new(big.Int).Div(defaultFeeInXDC, lendingTokenDecimal)
} else {
@ -473,10 +474,10 @@ func VerifyBalance(isXDCXLendingFork bool, statedb *state.StateDB, lendingStateD
}
return nil
default:
return fmt.Errorf("VerifyBalance: unknown lending side")
return errors.New("VerifyBalance: unknown lending side")
}
default:
return fmt.Errorf("VerifyBalance: unknown lending type")
return errors.New("VerifyBalance: unknown lending type")
}
return nil
}

View file

@ -114,12 +114,12 @@ func CheckRelayerFee(relayer common.Address, fee *big.Int, statedb *state.StateD
}
func AddTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
balance := statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD TOKEN XDC NATIVE BEFORE", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD TOKEN XDC NATIVE BEFORE", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
statedb.AddBalance(addr, value)
balance = statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD XDC NATIVE BALANCE AFTER", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: ADD XDC NATIVE BALANCE AFTER", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
return nil
}
@ -141,15 +141,15 @@ func AddTokenBalance(addr common.Address, value *big.Int, token common.Address,
func SubTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
balance := statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE BEFORE", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE BEFORE", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
if balance.Cmp(value) < 0 {
return errors.Errorf("value %s in token %s not enough , have : %s , want : %s ", addr.String(), token.String(), balance, value)
return errors.Errorf("value %s in token %s not enough , have : %s , want : %s ", addr.String(), common.XDCNativeAddress, balance, value)
}
statedb.SubBalance(addr, value)
balance = statedb.GetBalance(addr)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE AFTER", "token", token.String(), "address", addr.String(), "balance", balance, "orderValue", value)
log.Debug("ApplyXDCXMatchedTransaction settle balance: SUB XDC NATIVE BALANCE AFTER", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "orderValue", value)
return nil
}
@ -174,7 +174,7 @@ func SubTokenBalance(addr common.Address, value *big.Int, token common.Address,
func CheckSubTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB, mapBalances map[common.Address]map[common.Address]*big.Int) (*big.Int, error) {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
var balance *big.Int
if value := mapBalances[token][addr]; value != nil {
balance = value
@ -182,10 +182,10 @@ func CheckSubTokenBalance(addr common.Address, value *big.Int, token common.Addr
balance = statedb.GetBalance(addr)
}
if balance.Cmp(value) < 0 {
return nil, errors.Errorf("value %s in token %s not enough , have : %s , want : %s ", addr.String(), token.String(), balance, value)
return nil, errors.Errorf("value %s in token %s not enough , have : %s , want : %s ", addr.String(), common.XDCNativeAddress, balance, value)
}
newBalance := new(big.Int).Sub(balance, value)
log.Debug("CheckSubTokenBalance settle balance: SUB XDC NATIVE BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
log.Debug("CheckSubTokenBalance settle balance: SUB XDC NATIVE BALANCE ", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
return newBalance, nil
}
// TRC tokens
@ -211,7 +211,7 @@ func CheckSubTokenBalance(addr common.Address, value *big.Int, token common.Addr
func CheckAddTokenBalance(addr common.Address, value *big.Int, token common.Address, statedb *state.StateDB, mapBalances map[common.Address]map[common.Address]*big.Int) (*big.Int, error) {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
var balance *big.Int
if value := mapBalances[token][addr]; value != nil {
balance = value
@ -219,7 +219,7 @@ func CheckAddTokenBalance(addr common.Address, value *big.Int, token common.Addr
balance = statedb.GetBalance(addr)
}
newBalance := new(big.Int).Add(balance, value)
log.Debug("CheckAddTokenBalance settle balance: ADD XDC NATIVE BALANCE ", "token", token.String(), "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
log.Debug("CheckAddTokenBalance settle balance: ADD XDC NATIVE BALANCE ", "token", common.XDCNativeAddress, "address", addr.String(), "balance", balance, "value", value, "newBalance", newBalance)
return newBalance, nil
}
// TRC tokens
@ -263,7 +263,7 @@ func CheckSubRelayerFee(relayer common.Address, fee *big.Int, statedb *state.Sta
func GetTokenBalance(addr common.Address, token common.Address, statedb *state.StateDB) *big.Int {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
return statedb.GetBalance(addr)
}
// TRC tokens
@ -278,7 +278,7 @@ func GetTokenBalance(addr common.Address, token common.Address, statedb *state.S
func SetTokenBalance(addr common.Address, balance *big.Int, token common.Address, statedb *state.StateDB) error {
// XDC native
if token.String() == common.XDCNativeAddress {
if token == common.XDCNativeAddressBinary {
statedb.SetBalance(addr, balance)
return nil
}

View file

@ -3,9 +3,10 @@ package lendingstate
import (
"encoding/json"
"errors"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/log"
"math/big"
)
const DefaultFeeRate = 100 // 100 / XDCXBaseFee = 100 / 10000 = 1%
@ -71,7 +72,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("quantity lending too small", "quantityToLend", quantityToLend, "takerFee", takerFee)
return result, ErrQuantityTradeTooSmall
}
if lendingToken.String() != common.XDCNativeAddress && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
if lendingToken != common.XDCNativeAddressBinary && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
exTakerReceivedFee := new(big.Int).Mul(takerFee, lendTokenXDCPrice)
exTakerReceivedFee = new(big.Int).Div(exTakerReceivedFee, lendTokenDecimal)
@ -82,7 +83,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("takerFee too small", "quantityToLend", quantityToLend, "takerFee", takerFee, "exTakerReceivedFee", exTakerReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFeeInXDC", defaultFeeInXDC)
return result, ErrQuantityTradeTooSmall
}
} else if lendingToken.String() == common.XDCNativeAddress {
} else if lendingToken == common.XDCNativeAddressBinary {
exTakerReceivedFee := takerFee
if (exTakerReceivedFee.Cmp(common.RelayerLendingFee) <= 0 && exTakerReceivedFee.Sign() > 0) || defaultFee.Cmp(common.RelayerLendingFee) <= 0 {
log.Debug("takerFee too small", "quantityToLend", quantityToLend, "takerFee", takerFee, "exTakerReceivedFee", exTakerReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFee", defaultFee)
@ -121,7 +122,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("quantity lending too small", "quantityToLend", quantityToLend, "makerFee", makerFee)
return result, ErrQuantityTradeTooSmall
}
if lendingToken.String() != common.XDCNativeAddress && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
if lendingToken != common.XDCNativeAddressBinary && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
exMakerReceivedFee := new(big.Int).Mul(makerFee, lendTokenXDCPrice)
exMakerReceivedFee = new(big.Int).Div(exMakerReceivedFee, lendTokenDecimal)
@ -132,7 +133,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("makerFee too small", "quantityToLend", quantityToLend, "makerFee", makerFee, "exMakerReceivedFee", exMakerReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFeeInXDC", defaultFeeInXDC)
return result, ErrQuantityTradeTooSmall
}
} else if lendingToken.String() == common.XDCNativeAddress {
} else if lendingToken == common.XDCNativeAddressBinary {
exMakerReceivedFee := makerFee
if (exMakerReceivedFee.Cmp(common.RelayerLendingFee) <= 0 && exMakerReceivedFee.Sign() > 0) || defaultFee.Cmp(common.RelayerLendingFee) <= 0 {
log.Debug("makerFee too small", "quantityToLend", quantityToLend, "makerFee", makerFee, "exMakerReceivedFee", exMakerReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFee", defaultFee)
@ -171,7 +172,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("quantity lending too small", "quantityToLend", quantityToLend, "borrowFee", borrowFee)
return result, ErrQuantityTradeTooSmall
}
if lendingToken.String() != common.XDCNativeAddress && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
if lendingToken != common.XDCNativeAddressBinary && lendTokenXDCPrice != nil && lendTokenXDCPrice.Cmp(common.Big0) > 0 {
// exReceivedFee: the fee amount which borrowingRelayer will receive
exReceivedFee := new(big.Int).Mul(borrowFee, lendTokenXDCPrice)
exReceivedFee = new(big.Int).Div(exReceivedFee, lendTokenDecimal)
@ -183,7 +184,7 @@ func GetSettleBalance(isXDCXLendingFork bool,
log.Debug("takerFee too small", "quantityToLend", quantityToLend, "borrowFee", borrowFee, "exReceivedFee", exReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFeeInXDC", defaultFeeInXDC)
return result, ErrQuantityTradeTooSmall
}
} else if lendingToken.String() == common.XDCNativeAddress {
} else if lendingToken == common.XDCNativeAddressBinary {
exReceivedFee := borrowFee
if (exReceivedFee.Cmp(common.RelayerLendingFee) <= 0 && exReceivedFee.Sign() > 0) || defaultFee.Cmp(common.RelayerLendingFee) <= 0 {
log.Debug("takerFee too small", "quantityToLend", quantityToLend, "borrowFee", borrowFee, "exReceivedFee", exReceivedFee, "borrowFeeRate", borrowFeeRate, "defaultFee", defaultFee)

View file

@ -1,10 +1,11 @@
package lendingstate
import (
"github.com/XinFinOrg/XDPoSChain/common"
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
)
func TestCalculateInterestRate(t *testing.T) {
@ -171,7 +172,7 @@ func TestGetSettleBalance(t *testing.T) {
common.BasePrice,
big.NewInt(150),
big.NewInt(100), // 1%
common.HexToAddress(common.XDCNativeAddress),
common.XDCNativeAddressBinary,
common.Address{},
common.BasePrice,
common.BasePrice,
@ -277,7 +278,7 @@ func TestGetSettleBalance(t *testing.T) {
common.BasePrice,
big.NewInt(150),
big.NewInt(100), // 1%
common.HexToAddress(common.XDCNativeAddress),
common.XDCNativeAddressBinary,
collateral,
common.BasePrice,
common.BasePrice,
@ -288,12 +289,12 @@ func TestGetSettleBalance(t *testing.T) {
Fee: common.Big0,
InToken: common.Address{},
InTotal: common.Big0,
OutToken: common.HexToAddress(common.XDCNativeAddress),
OutToken: common.XDCNativeAddressBinary,
OutTotal: lendQuantity,
},
Maker: TradeResult{
Fee: fee,
InToken: common.HexToAddress(common.XDCNativeAddress),
InToken: common.XDCNativeAddressBinary,
InTotal: lendQuantityExcluded,
OutToken: collateral,
OutTotal: collateralLocked,
@ -312,7 +313,7 @@ func TestGetSettleBalance(t *testing.T) {
common.BasePrice,
big.NewInt(150),
big.NewInt(100), // 1%
common.HexToAddress(common.XDCNativeAddress),
common.XDCNativeAddressBinary,
collateral,
common.BasePrice,
common.BasePrice,
@ -323,12 +324,12 @@ func TestGetSettleBalance(t *testing.T) {
Fee: common.Big0,
InToken: common.Address{},
InTotal: common.Big0,
OutToken: common.HexToAddress(common.XDCNativeAddress),
OutToken: common.XDCNativeAddressBinary,
OutTotal: lendQuantity,
},
Taker: TradeResult{
Fee: fee,
InToken: common.HexToAddress(common.XDCNativeAddress),
InToken: common.XDCNativeAddressBinary,
InTotal: lendQuantityExcluded,
OutToken: collateral,
OutTotal: collateralLocked,

View file

@ -2,6 +2,7 @@ package XDCxlending
import (
"encoding/json"
"errors"
"fmt"
"math/big"
@ -264,7 +265,7 @@ func (l *Lending) processOrderList(header *types.Header, coinbase common.Address
borrowFee = lendingstate.GetFee(statedb, oldestOrder.Relayer)
}
if collateralToken.IsZero() {
return nil, nil, nil, fmt.Errorf("empty collateral")
return nil, nil, nil, errors.New("empty collateral")
}
depositRate, liquidationRate, recallRate := lendingstate.GetCollateralDetail(statedb, collateralToken)
if depositRate == nil || depositRate.Sign() <= 0 {
@ -282,10 +283,10 @@ func (l *Lending) processOrderList(header *types.Header, coinbase common.Address
return nil, nil, nil, err
}
if lendTokenXDCPrice == nil || lendTokenXDCPrice.Sign() <= 0 {
return nil, nil, nil, fmt.Errorf("invalid lendToken price")
return nil, nil, nil, errors.New("invalid lendToken price")
}
if collateralPrice == nil || collateralPrice.Sign() <= 0 {
return nil, nil, nil, fmt.Errorf("invalid collateral price")
return nil, nil, nil, errors.New("invalid collateral price")
}
tradedQuantity, collateralLockedAmount, rejectMaker, settleBalanceResult, err := l.getLendQuantity(lendTokenXDCPrice, collateralPrice, depositRate, borrowFee, coinbase, chain, header, statedb, order, &oldestOrder, maxTradedQuantity)
if err != nil && err == lendingstate.ErrQuantityTradeTooSmall && tradedQuantity != nil && tradedQuantity.Sign() >= 0 {
@ -447,7 +448,7 @@ func (l *Lending) getLendQuantity(
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)
}
if takerOrder.Relayer.String() == makerOrder.Relayer.String() {
if takerOrder.Relayer == makerOrder.Relayer {
if err := lendingstate.CheckRelayerFee(takerOrder.Relayer, new(big.Int).Mul(common.RelayerLendingFee, big.NewInt(2)), statedb); err != nil {
log.Debug("Reject order Taker Exchnage = Maker Exchange , relayer not enough fee ", "err", err)
return lendingstate.Zero, lendingstate.Zero, false, nil, nil
@ -621,11 +622,11 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *lendingsta
}
mapBalances[settleBalance.Taker.InToken][takerExOwner] = newTakerFee
newCollateralTokenLock, err := lendingstate.CheckAddTokenBalance(common.HexToAddress(common.LendingLockAddress), settleBalance.Taker.OutTotal, settleBalance.Taker.OutToken, statedb, mapBalances)
newCollateralTokenLock, err := lendingstate.CheckAddTokenBalance(common.LendingLockAddressBinary, settleBalance.Taker.OutTotal, settleBalance.Taker.OutToken, statedb, mapBalances)
if err != nil {
return err
}
mapBalances[settleBalance.Taker.OutToken][common.HexToAddress(common.LendingLockAddress)] = newCollateralTokenLock
mapBalances[settleBalance.Taker.OutToken][common.LendingLockAddressBinary] = newCollateralTokenLock
} else {
relayerFee, err := lendingstate.CheckSubRelayerFee(makerOrder.Relayer, common.RelayerLendingFee, statedb, map[common.Address]*big.Int{})
if err != nil {
@ -662,11 +663,11 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *lendingsta
}
mapBalances[settleBalance.Maker.InToken][makerExOwner] = newMakerFee
newCollateralTokenLock, err := lendingstate.CheckAddTokenBalance(common.HexToAddress(common.LendingLockAddress), settleBalance.Maker.OutTotal, settleBalance.Maker.OutToken, statedb, mapBalances)
newCollateralTokenLock, err := lendingstate.CheckAddTokenBalance(common.LendingLockAddressBinary, settleBalance.Maker.OutTotal, settleBalance.Maker.OutToken, statedb, mapBalances)
if err != nil {
return err
}
mapBalances[settleBalance.Maker.OutToken][common.HexToAddress(common.LendingLockAddress)] = newCollateralTokenLock
mapBalances[settleBalance.Maker.OutToken][common.LendingLockAddressBinary] = newCollateralTokenLock
}
masternodeOwner := statedb.GetOwner(coinbase)
statedb.AddBalance(masternodeOwner, matchingFee)
@ -789,10 +790,10 @@ func (l *Lending) ProcessTopUp(lendingStateDB *lendingstate.LendingStateDB, stat
if lendingTrade == lendingstate.EmptyLendingTrade {
return fmt.Errorf("process deposit for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId.Hex()), true, nil
}
if order.UserAddress.String() != lendingTrade.Borrower.String() {
if order.UserAddress != lendingTrade.Borrower {
return fmt.Errorf("ProcessTopUp: invalid userAddress . UserAddress: %s . Borrower: %s", order.UserAddress.Hex(), lendingTrade.Borrower.Hex()), true, nil
}
if order.Relayer.String() != lendingTrade.BorrowingRelayer.String() {
if order.Relayer != lendingTrade.BorrowingRelayer {
return fmt.Errorf("ProcessTopUp: invalid relayerAddress . Got: %s . Expect: %s", order.Relayer.Hex(), lendingTrade.BorrowingRelayer.Hex()), true, nil
}
if order.Quantity.Sign() <= 0 || lendingTrade.TradeId != lendingTradeId.Big().Uint64() {
@ -810,10 +811,10 @@ func (l *Lending) ProcessRepay(header *types.Header, chain consensus.ChainContex
if lendingTrade == lendingstate.EmptyLendingTrade || lendingTrade.TradeId != lendingTradeIdHash.Big().Uint64() {
return nil, fmt.Errorf("ProcessRepay for emptyLendingTrade is not allowed. lendingTradeId: %v", lendingTradeId)
}
if order.UserAddress.String() != lendingTrade.Borrower.String() {
if order.UserAddress != lendingTrade.Borrower {
return nil, fmt.Errorf("ProcessRepay: invalid userAddress . UserAddress: %s . Borrower: %s", order.UserAddress.Hex(), lendingTrade.Borrower.Hex())
}
if order.Relayer.String() != lendingTrade.BorrowingRelayer.String() {
if order.Relayer != lendingTrade.BorrowingRelayer {
return nil, fmt.Errorf("ProcessRepay: invalid relayerAddress . Got: %s . Expect: %s", order.Relayer.Hex(), lendingTrade.BorrowingRelayer.Hex())
}
return l.ProcessRepayLendingTrade(header, chain, lendingStateDB, statedb, tradingstateDB, lendingBook, lendingTradeId)
@ -854,9 +855,9 @@ func (l *Lending) LiquidationExpiredTrade(header *types.Header, chain consensus.
} else {
repayAmount = lendingTrade.CollateralLockedAmount
}
err = lendingstate.SubTokenBalance(common.HexToAddress(common.LendingLockAddress), lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
err = lendingstate.SubTokenBalance(common.LendingLockAddressBinary, lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
log.Warn("LiquidationExpiredTrade SubTokenBalance", "err", err, "LendingLockAddress", common.HexToAddress(common.LendingLockAddress), "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
log.Warn("LiquidationExpiredTrade SubTokenBalance", "err", err, "LendingLockAddress", common.LendingLockAddress, "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
err = lendingstate.AddTokenBalance(lendingTrade.Investor, repayAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
@ -897,9 +898,9 @@ func (l *Lending) LiquidationTrade(lendingStateDB *lendingstate.LendingStateDB,
if lendingTrade.TradeId != lendingTradeId {
return nil, fmt.Errorf("Lending Trade Id not found : %d ", lendingTradeId)
}
err := lendingstate.SubTokenBalance(common.HexToAddress(common.LendingLockAddress), lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
err := lendingstate.SubTokenBalance(common.LendingLockAddressBinary, lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
log.Warn("LiquidationTrade SubTokenBalance", "err", err, "LendingLockAddress", common.HexToAddress(common.LendingLockAddress), "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
log.Warn("LiquidationTrade SubTokenBalance", "err", err, "LendingLockAddress", common.LendingLockAddress, "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
err = lendingstate.AddTokenBalance(lendingTrade.Investor, lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
@ -1052,10 +1053,10 @@ func (l *Lending) GetCollateralPrices(header *types.Header, chain consensus.Chai
func (l *Lending) GetXDCBasePrices(header *types.Header, chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, token common.Address) (*big.Int, error) {
tokenXDCPriceFromContract, updatedBlock := lendingstate.GetCollateralPrice(statedb, token, common.HexToAddress(common.XDCNativeAddress))
tokenXDCPriceFromContract, updatedBlock := lendingstate.GetCollateralPrice(statedb, token, common.XDCNativeAddressBinary)
tokenXDCPriceUpdatedFromContract := updatedBlock.Uint64()/chain.Config().XDPoS.Epoch == header.Number.Uint64()/chain.Config().XDPoS.Epoch
if token == common.HexToAddress(common.XDCNativeAddress) {
if token == common.XDCNativeAddressBinary {
return common.BasePrice, nil
} else if tokenXDCPriceUpdatedFromContract {
// getting lendToken price from contract first
@ -1063,7 +1064,7 @@ func (l *Lending) GetXDCBasePrices(header *types.Header, chain consensus.ChainCo
log.Debug("Getting token/XDC price from contract", "price", tokenXDCPriceFromContract)
return tokenXDCPriceFromContract, nil
} else {
XDCTokenPriceFromContract, updatedBlock := lendingstate.GetCollateralPrice(statedb, common.HexToAddress(common.XDCNativeAddress), token)
XDCTokenPriceFromContract, updatedBlock := lendingstate.GetCollateralPrice(statedb, common.XDCNativeAddressBinary, token)
XDCTokenPriceUpdatedFromContract := updatedBlock.Uint64()/chain.Config().XDPoS.Epoch == header.Number.Uint64()/chain.Config().XDPoS.Epoch
if XDCTokenPriceUpdatedFromContract && XDCTokenPriceFromContract != nil && XDCTokenPriceFromContract.Sign() > 0 {
// getting lendToken price from contract first
@ -1078,7 +1079,7 @@ func (l *Lending) GetXDCBasePrices(header *types.Header, chain consensus.ChainCo
tokenXDCPrice = new(big.Int).Div(tokenXDCPrice, XDCTokenPriceFromContract)
return tokenXDCPrice, nil
}
tokenXDCPrice, err := l.GetMediumTradePriceBeforeEpoch(chain, statedb, tradingStateDb, token, common.HexToAddress(common.XDCNativeAddress))
tokenXDCPrice, err := l.GetMediumTradePriceBeforeEpoch(chain, statedb, tradingStateDb, token, common.XDCNativeAddressBinary)
if err != nil {
return nil, err
}
@ -1133,9 +1134,9 @@ func (l *Lending) ProcessTopUpLendingTrade(lendingStateDB *lendingstate.LendingS
if err != nil {
log.Warn("ProcessTopUpLendingTrade SubTokenBalance", "err", err, "lendingTrade.Borrower", lendingTrade.Borrower, "quantity", *quantity, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
err = lendingstate.AddTokenBalance(common.HexToAddress(common.LendingLockAddress), quantity, lendingTrade.CollateralToken, statedb)
err = lendingstate.AddTokenBalance(common.LendingLockAddressBinary, quantity, lendingTrade.CollateralToken, statedb)
if err != nil {
log.Warn("ProcessTopUpLendingTrade AddTokenBalance", "err", err, "LendingLockAddress", common.HexToAddress(common.LendingLockAddress), "quantity", *quantity, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
log.Warn("ProcessTopUpLendingTrade AddTokenBalance", "err", err, "LendingLockAddress", common.LendingLockAddress, "quantity", *quantity, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
oldLockedAmount := lendingTrade.CollateralLockedAmount
newLockedAmount := new(big.Int).Add(quantity, oldLockedAmount)
@ -1199,9 +1200,9 @@ func (l *Lending) ProcessRepayLendingTrade(header *types.Header, chain consensus
if err != nil {
log.Warn("ProcessRepayLendingTrade AddTokenBalance", "err", err, "lendingTrade.Investor", lendingTrade.Investor, "paymentBalance", *paymentBalance, "lendingTrade.LendingToken", lendingTrade.LendingToken)
}
err = lendingstate.SubTokenBalance(common.HexToAddress(common.LendingLockAddress), lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
err = lendingstate.SubTokenBalance(common.LendingLockAddressBinary, lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
log.Warn("ProcessRepayLendingTrade SubTokenBalance", "err", err, "LendingLockAddress", common.HexToAddress(common.LendingLockAddress), "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
log.Warn("ProcessRepayLendingTrade SubTokenBalance", "err", err, "LendingLockAddress", common.LendingLockAddress, "lendingTrade.CollateralLockedAmount", *lendingTrade.CollateralLockedAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
err = lendingstate.AddTokenBalance(lendingTrade.Borrower, lendingTrade.CollateralLockedAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
@ -1255,9 +1256,9 @@ func (l *Lending) ProcessRecallLendingTrade(lendingStateDB *lendingstate.Lending
if err != nil {
log.Warn("ProcessRecallLendingTrade AddTokenBalance", "err", err, "lendingTrade.Borrower", lendingTrade.Borrower, "recallAmount", *recallAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
err = lendingstate.SubTokenBalance(common.HexToAddress(common.LendingLockAddress), recallAmount, lendingTrade.CollateralToken, statedb)
err = lendingstate.SubTokenBalance(common.LendingLockAddressBinary, recallAmount, lendingTrade.CollateralToken, statedb)
if err != nil {
log.Warn("ProcessRecallLendingTrade SubTokenBalance", "err", err, "LendingLockAddress", common.HexToAddress(common.LendingLockAddress), "recallAmount", *recallAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
log.Warn("ProcessRecallLendingTrade SubTokenBalance", "err", err, "LendingLockAddress", common.LendingLockAddress, "recallAmount", *recallAmount, "lendingTrade.CollateralToken", lendingTrade.CollateralToken)
}
lendingStateDB.UpdateLiquidationPrice(lendingBook, lendingTrade.TradeId, newLiquidationPrice)

View file

@ -1,14 +1,15 @@
package XDCxlending
import (
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"reflect"
"testing"
)
func Test_getCancelFeeV1(t *testing.T) {
@ -107,9 +108,9 @@ func Test_getCancelFee(t *testing.T) {
XDCx.SetTokenDecimal(testTokenB, new(big.Int).Exp(big.NewInt(10), big.NewInt(8), nil))
// set tokenAPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenA, common.HexToAddress(common.XDCNativeAddress)), common.BasePrice)
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenA, common.XDCNativeAddressBinary), common.BasePrice)
// set tokenBPrice = 1 XDC
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenB, common.HexToAddress(common.XDCNativeAddress)), common.BasePrice)
tradingStateDb.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(testTokenB, common.XDCNativeAddressBinary), common.BasePrice)
l := New(XDCx)
@ -132,7 +133,7 @@ func Test_getCancelFee(t *testing.T) {
borrowFeeRate: common.Big0,
order: &lendingstate.LendingItem{
LendingToken: testTokenA,
CollateralToken: common.HexToAddress(common.XDCNativeAddress),
CollateralToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Investing,
},
@ -147,7 +148,7 @@ func Test_getCancelFee(t *testing.T) {
borrowFeeRate: common.Big0,
order: &lendingstate.LendingItem{
LendingToken: testTokenA,
CollateralToken: common.HexToAddress(common.XDCNativeAddress),
CollateralToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Borrowing,
},
@ -162,7 +163,7 @@ func Test_getCancelFee(t *testing.T) {
borrowFeeRate: new(big.Int).SetUint64(30), // 30/10000= 0.3%
order: &lendingstate.LendingItem{
LendingToken: testTokenA,
CollateralToken: common.HexToAddress(common.XDCNativeAddress),
CollateralToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Investing,
},
@ -177,7 +178,7 @@ func Test_getCancelFee(t *testing.T) {
borrowFeeRate: new(big.Int).SetUint64(30), // 30/10000= 0.3%
order: &lendingstate.LendingItem{
LendingToken: testTokenA,
CollateralToken: common.HexToAddress(common.XDCNativeAddress),
CollateralToken: common.XDCNativeAddressBinary,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Borrowing,
},
@ -194,7 +195,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
borrowFeeRate: common.Big0,
order: &lendingstate.LendingItem{
LendingToken: common.HexToAddress(common.XDCNativeAddress),
LendingToken: common.XDCNativeAddressBinary,
CollateralToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Investing,
@ -209,7 +210,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
borrowFeeRate: common.Big0,
order: &lendingstate.LendingItem{
LendingToken: common.HexToAddress(common.XDCNativeAddress),
LendingToken: common.XDCNativeAddressBinary,
CollateralToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Borrowing,
@ -224,7 +225,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
borrowFeeRate: new(big.Int).SetUint64(30), // 30/10000= 0.3%
order: &lendingstate.LendingItem{
LendingToken: common.HexToAddress(common.XDCNativeAddress),
LendingToken: common.XDCNativeAddressBinary,
CollateralToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Investing,
@ -239,7 +240,7 @@ func Test_getCancelFee(t *testing.T) {
CancelFeeArg{
borrowFeeRate: new(big.Int).SetUint64(30), // 30/10000= 0.3%
order: &lendingstate.LendingItem{
LendingToken: common.HexToAddress(common.XDCNativeAddress),
LendingToken: common.XDCNativeAddressBinary,
CollateralToken: testTokenA,
Quantity: new(big.Int).SetUint64(10000),
Side: lendingstate.Borrowing,

View file

@ -79,19 +79,19 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
// Unpack output in v according to the abi specification
func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
if len(output) == 0 {
return fmt.Errorf("abi: unmarshalling empty output")
return errors.New("abi: unmarshalling empty output")
}
// since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event
if method, ok := abi.Methods[name]; ok {
if len(output)%32 != 0 {
return fmt.Errorf("abi: improperly formatted output")
return errors.New("abi: improperly formatted output")
}
return method.Outputs.Unpack(v, output)
} else if event, ok := abi.Events[name]; ok {
return event.Inputs.Unpack(v, output)
}
return fmt.Errorf("abi: could not locate named method or event")
return errors.New("abi: could not locate named method or event")
}
// UnmarshalJSON implements json.Unmarshaler interface

View file

@ -25,11 +25,9 @@ import (
"sync"
"time"
"github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/XDCx"
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
@ -37,10 +35,10 @@ import (
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/bloombits"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
@ -365,7 +363,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
from := statedb.GetOrNewStateObject(call.From)
from.SetBalance(math.MaxBig256)
// Execute the call.
msg := callmsg{call}
msg := callMsg{call}
feeCapacity := state.GetTRC21FeeCapacityFromState(statedb)
if msg.To() != nil {
if value, ok := feeCapacity[*msg.To()]; ok {
@ -388,7 +386,10 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
b.mu.Lock()
defer b.mu.Unlock()
sender, err := types.Sender(types.HomesteadSigner{}, tx)
// Check transaction validity.
block := b.blockchain.CurrentBlock()
signer := types.MakeSigner(b.blockchain.Config(), block.Number())
sender, err := types.Sender(signer, tx)
if err != nil {
panic(fmt.Errorf("invalid transaction: %v", err))
}
@ -397,7 +398,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
}
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) {
// Include tx in chain.
blocks, _ := core.GenerateChain(b.config, block, b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTxWithChain(b.blockchain, tx)
}
@ -501,20 +503,21 @@ func (b *SimulatedBackend) GetBlockChain() *core.BlockChain {
return b.blockchain
}
// callmsg implements core.Message to allow passing it as a transaction simulator.
type callmsg struct {
// callMsg implements core.Message to allow passing it as a transaction simulator.
type callMsg struct {
XDPoSChain.CallMsg
}
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) To() *common.Address { return m.CallMsg.To }
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
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 }
func (m callmsg) BalanceTokenFee() *big.Int { return m.CallMsg.BalanceTokenFee }
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) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
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 }
func (m callMsg) BalanceTokenFee() *big.Int { return m.CallMsg.BalanceTokenFee }
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.

View file

@ -335,7 +335,7 @@ func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log)
return errNoEventSignature
}
if log.Topics[0] != c.abi.Events[event].Id() {
return fmt.Errorf("event signature mismatch")
return errors.New("event signature mismatch")
}
if len(log.Data) > 0 {
if err := c.abi.Unpack(out, event, log.Data); err != nil {

View file

@ -18,7 +18,7 @@ package bind
import (
"context"
"fmt"
"errors"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
@ -56,14 +56,14 @@ func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*ty
// contract address when it is mined. It stops waiting when ctx is canceled.
func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) (common.Address, error) {
if tx.To() != nil {
return common.Address{}, fmt.Errorf("tx is not contract creation")
return common.Address{}, errors.New("tx is not contract creation")
}
receipt, err := WaitMined(ctx, b, tx)
if err != nil {
return common.Address{}, err
}
if receipt.ContractAddress == (common.Address{}) {
return common.Address{}, fmt.Errorf("zero address")
return common.Address{}, errors.New("zero address")
}
// Check that code has indeed been deployed at the address.
// This matters on pre-Homestead chains: OOG in the constructor

View file

@ -17,6 +17,7 @@
package abi
import (
"errors"
"fmt"
"reflect"
)
@ -117,7 +118,7 @@ func requireUniqueStructFieldNames(args Arguments) error {
for _, arg := range args {
field := capitalise(arg.Name)
if field == "" {
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
return errors.New("abi: purely underscored output cannot unpack to struct")
}
if exists[field] {
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)

View file

@ -17,6 +17,7 @@
package abi
import (
"errors"
"fmt"
"reflect"
"regexp"
@ -61,7 +62,7 @@ var (
func NewType(t string) (typ Type, err error) {
// check that array brackets are equal if they exist
if strings.Count(t, "[") != strings.Count(t, "]") {
return Type{}, fmt.Errorf("invalid arg type in abi")
return Type{}, errors.New("invalid arg type in abi")
}
typ.stringKind = t
@ -98,7 +99,7 @@ func NewType(t string) (typ Type, err error) {
}
typ.Type = reflect.ArrayOf(typ.Size, embeddedType.Type)
} else {
return Type{}, fmt.Errorf("invalid formatting of array type")
return Type{}, errors.New("invalid formatting of array type")
}
return typ, err
}

View file

@ -18,6 +18,7 @@ package abi
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"reflect"
@ -70,7 +71,7 @@ func readBool(word []byte) (bool, error) {
// This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
if t.T != FunctionTy {
return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array")
return [24]byte{}, errors.New("abi: invalid type in call to make function type byte array")
}
if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 {
err = fmt.Errorf("abi: got improperly encoded function type, got %v", word)
@ -83,7 +84,7 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
// through reflection, creates a fixed array to be read from
func readFixedBytes(t Type, word []byte) (interface{}, error) {
if t.T != FixedBytesTy {
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
return nil, errors.New("abi: invalid type in call to make fixed byte array")
}
// convert
array := reflect.New(t.Type).Elem()
@ -123,7 +124,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
// declare our array
refSlice = reflect.New(t.Type).Elem()
} else {
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage")
return nil, errors.New("abi: invalid type in array/slice unpacking stage")
}
// Arrays have packed elements, resulting in longer unpack steps.

View file

@ -18,12 +18,14 @@
package accounts
import (
"fmt"
"math/big"
ethereum "github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/event"
"golang.org/x/crypto/sha3"
)
// Account represents an Ethereum account located at a specific location defined
@ -148,6 +150,34 @@ type Backend interface {
Subscribe(sink chan<- WalletEvent) event.Subscription
}
// TextHash is a helper function that calculates a hash for the given message that can be
// safely used to calculate a signature from.
//
// The hash is calulcated as
//
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
//
// This gives context to the signed message and prevents signing of transactions.
func TextHash(data []byte) []byte {
hash, _ := TextAndHash(data)
return hash
}
// TextAndHash is a helper function that calculates a hash for the given message that can be
// safely used to calculate a signature from.
//
// The hash is calulcated as
//
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
//
// This gives context to the signed message and prevents signing of transactions.
func TextAndHash(data []byte) ([]byte, string) {
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data))
hasher := sha3.NewLegacyKeccak256()
hasher.Write([]byte(msg))
return hasher.Sum(nil), msg
}
// WalletEventType represents the different event types that can be fired by
// the wallet subscription subsystem.
type WalletEventType int

View file

@ -17,6 +17,7 @@
package keystore
import (
"errors"
"fmt"
"math/rand"
"os"
@ -305,7 +306,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
select {
case <-ks.changes:
default:
return fmt.Errorf("wasn't notified of new accounts")
return errors.New("wasn't notified of new accounts")
}
return nil
}

View file

@ -24,7 +24,6 @@ import (
"crypto/ecdsa"
crand "crypto/rand"
"errors"
"fmt"
"math/big"
"os"
"path/filepath"
@ -288,11 +287,9 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b
if !found {
return nil, ErrLocked
}
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)
// Depending on the presence of the chain ID, sign with 2718 or homestead
signer := types.LatestSignerForChainID(chainID)
return types.SignTx(tx, signer, unlockedKey.PrivateKey)
}
// SignHashWithPassphrase signs hash if the private key matching the given address
@ -316,11 +313,9 @@ func (ks *KeyStore) SignTxWithPassphrase(a accounts.Account, passphrase string,
}
defer zeroKey(key.PrivateKey)
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil {
return types.SignTx(tx, types.NewEIP155Signer(chainID), key.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, key.PrivateKey)
// Depending on the presence of the chain ID, sign with or without replay protection.
signer := types.LatestSignerForChainID(chainID)
return types.SignTx(tx, signer, key.PrivateKey)
}
// Unlock unlocks the given account indefinitely.
@ -459,7 +454,7 @@ func (ks *KeyStore) Import(keyJSON []byte, passphrase, newPassphrase string) (ac
func (ks *KeyStore) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (accounts.Account, error) {
key := newKeyFromECDSA(priv)
if ks.cache.hasAddress(key.Address) {
return accounts.Account{}, fmt.Errorf("account already exists")
return accounts.Account{}, errors.New("account already exists")
}
return ks.importKey(key, passphrase)
}

View file

@ -27,13 +27,13 @@ import (
"io"
"math/big"
"github.com/golang/protobuf/proto"
"github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/usbwallet/internal/trezor"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/golang/protobuf/proto"
)
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
@ -80,13 +80,13 @@ func (w *trezorDriver) Status() (string, error) {
// Open implements usbwallet.driver, attempting to initialize the connection to
// the Trezor hardware wallet. Initializing the Trezor is a two phase operation:
// * The first phase is to initialize the connection and read the wallet's
// features. This phase is invoked is the provided passphrase is empty. The
// device will display the pinpad as a result and will return an appropriate
// error to notify the user that a second open phase is needed.
// * The second phase is to unlock access to the Trezor, which is done by the
// user actually providing a passphrase mapping a keyboard keypad to the pin
// number of the user (shuffled according to the pinpad displayed).
// - The first phase is to initialize the connection and read the wallet's
// features. This phase is invoked is the provided passphrase is empty. The
// device will display the pinpad as a result and will return an appropriate
// error to notify the user that a second open phase is needed.
// - The second phase is to unlock access to the Trezor, which is done by the
// user actually providing a passphrase mapping a keyboard keypad to the pin
// number of the user (shuffled according to the pinpad displayed).
func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
w.device, w.failure = device, nil
@ -220,9 +220,11 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
if chainID == nil {
signer = new(types.HomesteadSigner)
} else {
// Trezor backend does not support typed transactions yet.
signer = types.NewEIP155Signer(chainID)
signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
}
// Inject the final signature into the transaction and sanity check the sender
signed, err := tx.WithSignature(signer, signature)
if err != nil {

View file

@ -19,6 +19,7 @@ package bmt
import (
"bytes"
crand "crypto/rand"
"errors"
"fmt"
"hash"
"io"
@ -288,7 +289,7 @@ func TestHasherConcurrency(t *testing.T) {
var err error
select {
case <-time.NewTimer(5 * time.Second).C:
err = fmt.Errorf("timed out")
err = errors.New("timed out")
case err = <-errc:
}
if err != nil {
@ -321,7 +322,7 @@ func testHasherCorrectness(bmt hash.Hash, hasher BaseHasher, d []byte, n, count
}()
select {
case <-timeout.C:
err = fmt.Errorf("BMT hash calculation timed out")
err = errors.New("BMT hash calculation timed out")
case err = <-c:
}
return err

View file

@ -55,7 +55,7 @@ echo "Running a node with wallet: ${wallet} at local"
--datadir ./tmp/xdcchain --networkid 551 \
-port 30303 --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport 8545 \
--rpcapi admin,db,eth,debug,miner,net,shh,txpool,personal,web3,XDPoS \
--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 \

View file

@ -77,7 +77,7 @@ XDC --ethstats ${netstats} --gcmode archive \
--datadir /work/xdcchain --networkid 551 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi admin,db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \

View file

@ -76,7 +76,7 @@ XDC --ethstats ${netstats} --gcmode archive \
--datadir /work/xdcchain --networkid 50 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi admin,db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \

View file

@ -86,6 +86,7 @@ module "devnet_rpc" {
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
volume_size = 1500
providers = {
aws = aws.ap-southeast-1
@ -101,6 +102,7 @@ module "testnet_rpc" {
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
volume_size = 1500
providers = {
aws = aws.ap-southeast-1
@ -116,6 +118,7 @@ module "mainnet_rpc" {
instance_type = "t3.large"
ssh_key_name = local.ssh_key_name
rpc_image = local.rpc_image
volume_size = 3000
providers = {
aws = aws.ap-southeast-1

View file

@ -27,6 +27,9 @@ variable ssh_key_name {
variable rpc_image {
type = string
}
variable volume_size{
type = number
}
resource "aws_security_group" "rpc_sg" {
name_prefix = "${var.network}_rpc_sg"
@ -75,9 +78,9 @@ resource "aws_instance" "rpc_instance" {
}
key_name = var.ssh_key_name
vpc_security_group_ids = [aws_security_group.rpc_sg.id]
ebs_block_device {
device_name = "/dev/xvda"
volume_size = 500
root_block_device {
volume_size = var.volume_size
}

View file

@ -1,9 +1,39 @@
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@188.227.164.51:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@95.179.217.201:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@149.28.167.190:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@194.233.77.19:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@144.91.108.231:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@207.244.240.232:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@66.94.121.62:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@144.126.150.69:30301
enode://1c20e6b46ce608c1fe739e78611225b94e663535b74a1545b1667eac8ff75ed43216306d123306c10e043f228e42cc53cb2728655019292380313393eaaf6e23@161.97.93.168:30301
enode://278a1ac8aab1381b460788dcf4dcaffd58252f0f4c57d95e4c68b4b2bbf0b0fee83b5c140b3e6eb3af8b8369e76fa6996ccc667f65f9ce35c1d14fbffbfdfd52@95.179.217.201:30301
enode://518a2b963f0e41ef6520973766a8caad9b13c4261c50a73eedfeaa3ebf3cce623dadc132d8d42ec41a50195c925ca55abd4e2a96258f9d335e3f625e6c2df789@149.28.167.190:30301
enode://63f5a65ffce84b7123562b8bc871ae63db6dadded14df1dae6ad09b4a30e722a72e522d99aaf0bbad19380a0dd3abe94768ed03a8f68204b5dee6ae16ddb4d83@194.233.77.19:30301
enode://87497c34ce0102e888040d6ec530e73c33bb0330770105797cf5667f465115d49d53cb583a8b4e34ff14048448c63f03fbd1c269897d7b99716dcdb942b6d707@144.91.108.231:30301
enode://8c372fc5859e69a49037768f2ece54f14d1d159ec3181d06d7b58f1a54dac4f2f13623f1377a7e506e48e5f33b1752a9726a44b33fdb158ce7d6d5a57c055f65@207.244.240.232:30301
enode://bed408a65f2894b09ac11ec03eee6b4b1af279e27c81fbe942aa6300ebe5d734913c0c7b30cdbcf98dfebd7a46bf9c79cfc1a8878e20240b5da872dc358be571@66.94.121.62:30301
enode://dd8973429effba6d6f8edd27efad8544553bb39c82c6350c09e82cd3cfdcdecaf6d0ce9820ed97482aedd0b9236e88d362ca031a65dcbdac52aa292e693723e3@144.126.150.69:30301
enode://fb5616c009265a162c08fb3984192ffc4df18946dc4d591ba5480011169e6f3f324685b5e102e8123d32e27cd968220d6400b9f1f0a6d1611c130079cd1e71bb@161.97.93.168:30301
enode://75e95709fd89a6314b0d5363226e3e46c56d98c6ddd3ec3cbdffcb65fdfedc8cbad870e2af1382b97e5986c1465cdb00e621cc01e1910f622ba20ed2359a02a0@213.136.89.186:30304
enode://34ba74c6a0ef379040243e19c5f673b29155ec5928a5300f1cdfd2215983b7720d52585acb16f7199cc5abdd9ff3657305e901e097f951e35740b0a80fce3e18@185.217.126.17:30304
enode://d7c070939155be296a8b254d43a0927e6c6777f1352239499fab867af455b9c671bddd5f9ae359ddcd6af9a368746e2f993416bafff2d03a4d974d888daaf020@38.242.244.116:30304
enode://0ad61fd32bcc99b32f6ead959f2f3472ecd11cd5b555767983b1827240cbac25fd978b94cf79ca8423088e5dd519479a6f7f26fe43a98e0da0b4b1caa995923d@207.180.210.192:30304
enode://0985cfee342bf68bc21fea7ce728018d3a5f27a43a2c79b78e9103d07ac4893960fc399603d372744dfe2020a970a1daba979210e07c1d27bf6cfc317036ae13@173.249.33.28:30304
enode://4c750ba2c069e00a8bbe37e45053e04a975a4cc635f1c53506da555bc9cc137da2680b76f48a232b88f762153af83aced601ad45475576100f175c0085750822@209.145.57.76:30304
enode://d31b551d02ead096d5cbb3adda68fbcfbc76e4f939a6a6fe41e1a4e1be19c6f4b1c45a7545977764267d8bc6b7d1835c0e2060045a223af8ebb81d5cd30d01de@5.189.132.151:30304
enode://686d8c5b886bf29633b73e5b4f7eb73cb1afa8c11cd5d3cc79027b742eeaff62fe44a42417d18c2d96ff8de2bf2c0c73ce51a07f3d5635b232e2eece090234b6@164.68.125.57:30304
enode://7325b2eca70dfb9bde340ccfb6a5076f146f2af2401fae7996044207c95c797c2be4c0d90d76183abfdf33395553d6eb05fff6259c8fbe1df884df85d59f40b0@31.220.84.216:30304
enode://f8e45296452c4e3988f9398bee1e1be029993a5332bd293629397dd71cca281fd7aaa3ade4d92c63a984218a6dd7ffddcd70135cfd5b3a66e0dd124dc9c35a37@31.220.84.220:30304
enode://d8d8dff11b36dd683daccbb0306be706d97838dc0239aca077ab5475cbd488f9ebafa9a4a242d87f6def31028969756060ea412621d83a4715bd9a47e0787d3d@31.220.84.222:30304
enode://0d3a38063c594523dbd619033ecc6b87545b204e91aa883b789389483baca964fcc4221832ea470308e1faa56b90705be234a113d63a3f0f7347d1237b58fec2@31.220.84.224:30304
enode://1f479698e303b5ee9b8d35cdc6c660486b39a3f3f4581a1ecae5464142bef3103abe8665f1e25c864decaf80ee1261c2dc6f4f0caf2a2a66708fe934a63a564c@158.220.87.132:30304
enode://6dd64c63402ebe46c1043c97ce66b7de88fb220b45f7435964bbfe6af2f3d0bf4d6b4702c274231afdab7d246054f85414befbe6ed0086aa5e9d98272e931278@158.220.87.144:30304
enode://587d3c6962fedf45f07c758b5d7e07fbd3570e599a69f82d3f4676012327a92644785599ceaac9a35ed4f35478bd3dfe0dd4788b4529fa05cef15ba2e611f045@84.46.248.126:30304
enode://e9684ecbf96348727f21d1d2253893aa2c5815dd8d9e0e2f8e842dfd92347d1daab1c2cea3a379a66fd6bf5321945eb65cc794a10345a4e1ec0a0121b77481d3@185.209.230.34:30304
enode://52744d57d65b91fa2ccc43cb5758fca34f97509b068fc1fe1daee4d905cfbae7172a1647c28583b97fc51aaf0bf23b4e47340e2e658fcd5683daaa91c8d41c5d@167.86.125.253:30304
enode://09aa42d01437643d3f2a02e12e0d6e41a6951281ef80d2a332dd025d5da0d4990b9932695f91ffb0a0998cec2531dc9c0e8e0fd4a3bb0b69409ad76c02da9f4e@167.86.125.15:30304
enode://017ef59b3f3734aad9277170cd08c2a3231c75a63465085584ca00ffb32daccd2dfe657b2a3539af1d45e6b24251a18f2bc1b0e31b61f57c2039af95ebda1e2c@95.111.237.15:30304
enode://e3eb10d6616dc9dbe6006bafbe02fceaef60bcce66666ef357b458e91df64b33572014ea2a162873ec6a68af80a405cc0a60e8125f8ec155be7e34caa4e8aeb6@173.212.253.234:30304
enode://cbba3cf7f151bf79319107d0f24ca0fed9d6bc32bd922b173e5b87174fedd1d25378cf827236f05c00ce403a68d2ba75dda28e16ca43cbe87b0231a9ad16426e@178.18.249.111:30304
enode://8b9a5f0433ed2dcb7fe0e4424ae6f83158cc73a562c8c5c1733a01eb2c92c1b77ffb46dc1f4b54d8b2392d9fd985661b968d9d062ffc73ece02b58f41589527a@173.249.54.137:30304
enode://38d42a90e8c00beff03dc2f759a00e2f910b5bfd7b9eaafab3f24682c5e0bd2ae7094823a1af006295922848e3e417188f90766840220f377a780c8c5afa4c47@38.242.129.33:30304
enode://e9efc55e68dbc38842c5ed43c597d7550d31d2c9d7e074e14a43a9304fa2eb8a2ad0955eef1961e6c5b850ce2061479623ba2ad8ae22db944f17fd4a19a8b902@167.86.106.195:30304
enode://0c5dc604acbf5f04bd69e015e89c1c015f2641f5dbe8f56c0b2dc1d03e7b7d79e049ed3cca6b0f23cfecfd32c394a53e3d3810b0c4784b92646e658e1d879bf6@84.21.171.77:30304
enode://a1dd03c142c2db1a786e51250e929f2bf5edf7575f23ecfedec6da4a51e89e7ed36479fb4f40677da496364894b97ab189475fbb6c8b7ca2ecfe4b3ff3d24ca9@85.208.51.215:30304
enode://94389b49ca856a91b9962ead5a562a64383b7f8fdb819b6fa22d29db984a78b89245e894b8c29facc765348399e1dc4d4a16a787f94f21df8813bc7e703db4fc@167.86.118.99:30304
enode://b786080fabb1b07046359c1820db88c589c6c4a964ec8b1f1a287c12c4178dec2fbbf406187e16dc29fd69cc5e4960741471bebbfe2ae111036f66b61f16cf41@38.242.129.40:30304
enode://326d2d562754cdd72e1a4b7d42de44713d97f00c4b6e7250e6896b99d331a395012fe0cc6a2d133bdd8784e02649eb490197b65244f72003fff0c829d8695cb4@167.86.83.167:30304
enode://c85d71dfb2dfc5abd832ed60bc0197ecb788d0f6bd44655d870dec6002a23345790344d65a2cfc0d2c0e023a7a6f630f99b6575cf5ca57203870f1971d1fc370@167.86.83.166:30304

View file

@ -78,7 +78,7 @@ XDC --ethstats ${netstats} --gcmode archive \
--datadir /work/xdcchain --networkid 51 \
-port $port --rpc --rpccorsdomain "*" --rpcaddr 0.0.0.0 \
--rpcport $rpc_port \
--rpcapi admin,db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \
--rpcvhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \
--gasprice "1" --targetgaslimit "420000000" --verbosity ${log_level} \
--debugdatadir /work/xdcchain \

View file

@ -33,15 +33,23 @@ type JSONLogger struct {
}
func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer), cfg}
l := &JSONLogger{json.NewEncoder(writer), cfg}
if l.cfg == nil {
l.cfg = &vm.LogConfig{}
}
return l
}
func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
return nil
func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
func (l *JSONLogger) CaptureFault(*vm.EVM, uint64, vm.OpCode, uint64, uint64, *vm.ScopeContext, int, error) {
}
// CaptureState outputs state information on the logger.
func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
memory := scope.Memory
stack := scope.Stack
log := vm.StructLog{
Pc: pc,
Op: op,
@ -63,24 +71,20 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
}
log.Stack = logstack
}
return l.encoder.Encode(log)
}
// CaptureFault outputs state information on the logger.
func (l *JSONLogger) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
return nil
l.encoder.Encode(log)
}
// CaptureEnd is triggered at end of execution.
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
type endLog struct {
Output string `json:"output"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
Time time.Duration `json:"time"`
Err string `json:"error,omitempty"`
}
var errMsg string
if err != nil {
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
errMsg = err.Error()
}
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, errMsg})
}

View file

@ -28,7 +28,7 @@ var (
cacheSize = flag.Int("size", 1000000, "LRU cache size")
sercureKey = []byte("secure-key-")
nWorker = runtime.NumCPU() / 2
cleanAddress = []common.Address{common.HexToAddress(common.BlockSigners)}
cleanAddress = []common.Address{common.BlockSignersBinary}
cache *lru.Cache
finish = int32(0)
running = true

View file

@ -145,8 +145,8 @@ func (w *wizard) makeGenesis() {
genesis.Config.XDPoS.V2.CurrentConfig.TimeoutSyncThreshold = w.readDefaultInt(3)
fmt.Println()
fmt.Printf("How many v2 vote collection to generate a QC, should be two thirds of masternodes? (default = %f)\n", 0.666)
genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.666)
fmt.Printf("Proportion of total masternodes v2 vote collection to generate a QC (float value), should be two thirds of masternodes? (default = %f)\n", 0.667)
genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.667)
genesis.Config.XDPoS.V2.AllConfigs[0] = genesis.Config.XDPoS.V2.CurrentConfig
@ -197,7 +197,7 @@ func (w *wizard) makeGenesis() {
fmt.Println()
fmt.Println("What is foundation wallet address? (default = xdc0000000000000000000000000000000000000068)")
genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.HexToAddress(common.FoudationAddr))
genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.FoudationAddrBinary)
// Validator Smart Contract Code
pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
@ -225,7 +225,7 @@ func (w *wizard) makeGenesis() {
return true
}
contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.MasternodeVotingSMC)] = core.GenesisAccount{
genesis.Alloc[common.MasternodeVotingSMCBinary] = core.GenesisAccount{
Balance: validatorCap.Mul(validatorCap, big.NewInt(int64(len(validatorCaps)))),
Code: code,
Storage: storage,
@ -259,7 +259,7 @@ func (w *wizard) makeGenesis() {
fBalance := big.NewInt(0) // 16m
fBalance.Add(fBalance, big.NewInt(16*1000*1000))
fBalance.Mul(fBalance, big.NewInt(1000000000000000000))
genesis.Alloc[common.HexToAddress(common.FoudationAddr)] = core.GenesisAccount{
genesis.Alloc[common.FoudationAddrBinary] = core.GenesisAccount{
Balance: fBalance,
Code: code,
Storage: storage,
@ -275,7 +275,7 @@ func (w *wizard) makeGenesis() {
code, _ = contractBackend.CodeAt(ctx, blockSignerAddress, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, blockSignerAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.BlockSigners)] = core.GenesisAccount{
genesis.Alloc[common.BlockSignersBinary] = core.GenesisAccount{
Balance: big.NewInt(0),
Code: code,
Storage: storage,
@ -291,7 +291,7 @@ func (w *wizard) makeGenesis() {
code, _ = contractBackend.CodeAt(ctx, randomizeAddress, nil)
storage = make(map[common.Hash]common.Hash)
contractBackend.ForEachStorageAt(ctx, randomizeAddress, nil, f)
genesis.Alloc[common.HexToAddress(common.RandomizeSMC)] = core.GenesisAccount{
genesis.Alloc[common.RandomizeSMCBinary] = core.GenesisAccount{
Balance: big.NewInt(0),
Code: code,
Storage: storage,
@ -330,7 +330,7 @@ func (w *wizard) makeGenesis() {
subBalance.Add(subBalance, big.NewInt(int64(len(signers))*50*1000))
subBalance.Mul(subBalance, big.NewInt(1000000000000000000))
balance.Sub(balance, subBalance) // 12m - i * 50k
genesis.Alloc[common.HexToAddress(common.TeamAddr)] = core.GenesisAccount{
genesis.Alloc[common.TeamAddrBinary] = core.GenesisAccount{
Balance: balance,
Code: code,
Storage: storage,

View file

@ -19,6 +19,7 @@ package utils
import (
"compress/gzip"
"errors"
"fmt"
"io"
"os"
@ -130,7 +131,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
for batch := 0; ; batch++ {
// Load a batch of RLP blocks.
if checkInterrupt() {
return fmt.Errorf("interrupted")
return errors.New("interrupted")
}
i := 0
for ; i < importBatchSize; i++ {
@ -153,7 +154,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
}
// Import the batch.
if checkInterrupt() {
return fmt.Errorf("interrupted")
return errors.New("interrupted")
}
missing := missingBlocks(chain, blocks[:i])
if len(missing) == 0 {

View file

@ -118,7 +118,7 @@ var (
Enable0xPrefixFlag = cli.BoolFlag{
Name: "enable-0x-prefix",
Usage: "Addres use 0x-prefix (Deprecated: this is on by default, to use xdc prefix use --enable-xdc-prefix)",
}
}
EnableXDCPrefixFlag = cli.BoolFlag{
Name: "enable-xdc-prefix",
Usage: "Addres use xdc-prefix (default = false)",
@ -358,6 +358,11 @@ var (
Name: "vmdebug",
Usage: "Record information useful for VM and contract debugging",
}
RPCGlobalGasCapFlag = cli.Uint64Flag{
Name: "rpc.gascap",
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)",
Value: eth.DefaultConfig.RPCGasCap,
}
// Logging and debug settings
EthStatsURLFlag = cli.StringFlag{
Name: "ethstats",
@ -1176,6 +1181,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
// TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
}
if cfg.RPCGasCap != 0 {
log.Info("Set global gas cap", "cap", cfg.RPCGasCap)
} else {
log.Info("Global gas cap disabled")
}
if ctx.GlobalIsSet(StoreRewardFlag.Name) {
common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards")
if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) {

View file

@ -139,8 +139,8 @@ func processArgs() {
}
if *asymmetricMode && len(*argPub) > 0 {
pub = crypto.ToECDSAPub(common.FromHex(*argPub))
if !isKeyValid(pub) {
var err error
if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
utils.Fatalf("invalid public key")
}
}
@ -337,9 +337,8 @@ func configureNode() {
if b == nil {
utils.Fatalf("Error: can not convert hexadecimal string")
}
pub = crypto.ToECDSAPub(b)
if !isKeyValid(pub) {
utils.Fatalf("Error: invalid public key")
if pub, err = crypto.UnmarshalPubkey(b); err != nil {
utils.Fatalf("Error: invalid peer public key")
}
}
}

View file

@ -47,11 +47,12 @@ var TIPXDCXCancellationFee = big.NewInt(38383838)
var TIPXDCXCancellationFeeTestnet = big.NewInt(38383838)
var TIPXDCXMinerDisable = big.NewInt(88999999900)
var TIPXDCXReceiverDisable = big.NewInt(99999999999)
var BerlinBlock = big.NewInt(9999999999)
var LondonBlock = big.NewInt(9999999999)
var MergeBlock = big.NewInt(9999999999)
var ShanghaiBlock = big.NewInt(9999999999)
var Eip1559Block = big.NewInt(9999999999)
var TIPXDCXDISABLE = big.NewInt(99999999900)
var BerlinBlock = big.NewInt(76321000) // Target 19th June 2024
var LondonBlock = big.NewInt(76321000) // Target 19th June 2024
var MergeBlock = big.NewInt(76321000) // Target 19th June 2024
var ShanghaiBlock = big.NewInt(76321000) // Target 19th June 2024
var TIPXDCXTestnet = big.NewInt(38383838)
var IsTestnet bool = false

View file

@ -1,7 +1,7 @@
package countdown
import (
"fmt"
"errors"
"testing"
"time"
@ -76,7 +76,7 @@ func TestCountdownShouldResetEvenIfErrored(t *testing.T) {
called := make(chan int)
OnTimeoutFn := func(time.Time, interface{}) error {
called <- 1
return fmt.Errorf("ERROR!")
return errors.New("ERROR!")
}
countdown := NewCountDown(5000 * time.Millisecond)

View file

@ -50,6 +50,20 @@ const (
XDCZApplyMethod = "0xc6b32f34"
)
var (
BlockSignersBinary = Address{19: 0x89} // xdc0000000000000000000000000000000000000089
MasternodeVotingSMCBinary = Address{19: 0x88} // xdc0000000000000000000000000000000000000088
RandomizeSMCBinary = Address{19: 0x90} // xdc0000000000000000000000000000000000000090
FoudationAddrBinary = Address{19: 0x68} // xdc0000000000000000000000000000000000000068
TeamAddrBinary = Address{19: 0x99} // xdc0000000000000000000000000000000000000099
XDCXAddrBinary = Address{19: 0x91} // xdc0000000000000000000000000000000000000091
TradingStateAddrBinary = Address{19: 0x92} // xdc0000000000000000000000000000000000000092
XDCXLendingAddressBinary = Address{19: 0x93} // xdc0000000000000000000000000000000000000093
XDCXLendingFinalizedTradeAddressBinary = Address{19: 0x94} // xdc0000000000000000000000000000000000000094
XDCNativeAddressBinary = Address{19: 0x01} // xdc0000000000000000000000000000000000000001
LendingLockAddressBinary = Address{19: 0x11} // xdc0000000000000000000000000000000000000011
)
var (
hashT = reflect.TypeOf(Hash{})
addressT = reflect.TypeOf(Address{})
@ -256,7 +270,7 @@ func (a *Address) Set(other Address) {
// MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) {
// Handle '0x' or 'xdc' prefix here.
if (Enable0xPrefix) {
if Enable0xPrefix {
return hexutil.Bytes(a[:]).MarshalText()
} else {
return hexutil.Bytes(a[:]).MarshalXDCText()

View file

@ -167,3 +167,39 @@ func TestRemoveItemInArray(t *testing.T) {
t.Error("fail remove item from array address")
}
}
var testCases = []struct {
bin Address
str string
}{
{BlockSignersBinary, BlockSigners},
{MasternodeVotingSMCBinary, MasternodeVotingSMC},
{RandomizeSMCBinary, RandomizeSMC},
{FoudationAddrBinary, FoudationAddr},
{TeamAddrBinary, TeamAddr},
{XDCXAddrBinary, XDCXAddr},
{TradingStateAddrBinary, TradingStateAddr},
{XDCXLendingAddressBinary, XDCXLendingAddress},
{XDCXLendingFinalizedTradeAddressBinary, XDCXLendingFinalizedTradeAddress},
{XDCNativeAddressBinary, XDCNativeAddress},
{LendingLockAddressBinary, LendingLockAddress},
}
func TestBinaryAddressToString(t *testing.T) {
for _, tt := range testCases {
have := tt.bin.String()
want := tt.str
if have != want {
t.Errorf("fail to convert binary address to string address\nwant:%s\nhave:%s", have, want)
}
}
}
func TestStringToBinaryAddress(t *testing.T) {
for _, tt := range testCases {
want := tt.bin
have := HexToAddress(tt.str)
if have != want {
t.Errorf("fail to convert string address to binary address\nwant:%s\nhave:%s", have, want)
}
}
}

View file

@ -17,6 +17,7 @@
package XDPoS
import (
"errors"
"fmt"
"math/big"
@ -438,7 +439,7 @@ func (x *XDPoS) CalculateMissingRounds(chain consensus.ChainReader, header *type
case params.ConsensusEngineVersion2:
return x.EngineV2.CalculateMissingRounds(chain, header)
default: // Default "v1"
return nil, fmt.Errorf("Not supported in the v1 consensus")
return nil, errors.New("Not supported in the v1 consensus")
}
}

View file

@ -259,7 +259,7 @@ func (api *API) GetV2BlockByHash(blockHash common.Hash) *V2BlockInfo {
func (api *API) NetworkInformation() NetworkInformation {
info := NetworkInformation{}
info.NetworkId = api.chain.Config().ChainId
info.XDCValidatorAddress = common.HexToAddress(common.MasternodeVotingSMC)
info.XDCValidatorAddress = common.MasternodeVotingSMCBinary
if common.IsTestnet {
info.LendingAddress = common.HexToAddress(common.LendingRegistrationSMCTestnet)
info.RelayerRegistrationAddress = common.HexToAddress(common.RelayerRegistrationSMCTestnet)

View file

@ -686,7 +686,7 @@ func (x *XDPoS_v1) GetValidator(creator common.Address, chain consensus.ChainRea
if no%epoch == 0 {
cpHeader = header
} else {
return common.Address{}, fmt.Errorf("couldn't find checkpoint header")
return common.Address{}, errors.New("couldn't find checkpoint header")
}
}
m, err := getM1M2FromCheckpointHeader(cpHeader, header, chain.Config())

View file

@ -661,7 +661,7 @@ func (x *XDPoS_v2) VerifyTimeoutMessage(chain consensus.ChainReader, timeoutMsg
}
if len(snap.NextEpochCandidates) == 0 {
log.Error("[VerifyTimeoutMessage] cannot find NextEpochCandidates from snapshot", "messageGapNumber", timeoutMsg.GapNumber)
return false, fmt.Errorf("Empty master node lists from snapshot")
return false, errors.New("Empty master node lists from snapshot")
}
verified, signer, err := x.verifyMsgSignature(types.TimeoutSigHash(&types.TimeoutForSign{
@ -748,7 +748,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
// If blockHeader present, then its value shall consistent with what's provided in the blockInfo
if blockHeader.Hash() != blockInfo.Hash {
log.Warn("[VerifyBlockInfo] BlockHeader and blockInfo mismatch", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockHeaderHash", blockHeader.Hash())
return fmt.Errorf("[VerifyBlockInfo] Provided blockheader does not match what's in the blockInfo")
return errors.New("[VerifyBlockInfo] Provided blockheader does not match what's in the blockInfo")
}
}
@ -761,7 +761,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
if blockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
if blockInfo.Round != 0 {
log.Error("[VerifyBlockInfo] Switch block round is not 0", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number)
return fmt.Errorf("[VerifyBlockInfo] switch block round have to be 0")
return errors.New("[VerifyBlockInfo] switch block round have to be 0")
}
return nil
}
@ -789,7 +789,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, quorumCert.ProposedBlockInfo.Hash)
if err != nil {
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
return fmt.Errorf("Fail to verify QC due to failure in getting epoch switch info")
return errors.New("Fail to verify QC due to failure in getting epoch switch info")
}
signatures, duplicates := UniqueSignatures(quorumCert.Signatures)
@ -821,12 +821,12 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
}), sig, epochInfo.Masternodes)
if err != nil {
log.Error("[verifyQC] Error while verfying QC message signatures", "Error", err)
haveError = fmt.Errorf("Error while verfying QC message signatures")
haveError = errors.New("Error while verfying QC message signatures")
return
}
if !verified {
log.Warn("[verifyQC] Signature not verified doing QC verification", "QC", quorumCert)
haveError = fmt.Errorf("Fail to verify QC due to signature mis-match")
haveError = errors.New("Fail to verify QC due to signature mis-match")
return
}
}(signature)

View file

@ -2,6 +2,7 @@ package engine_v2
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"reflect"
@ -49,7 +50,7 @@ func (f *Forensics) SetCommittedQCs(headers []types.Header, incomingQC types.Quo
// highestCommitQCs is an array, assign the parentBlockQc and its child as well as its grandchild QC into this array for forensics purposes.
if len(headers) != NUM_OF_FORENSICS_QC-1 {
log.Error("[SetCommittedQcs] Received input length not equal to 2", len(headers))
return fmt.Errorf("received headers length not equal to 2 ")
return errors.New("received headers length not equal to 2 ")
}
var committedQCs []types.QuorumCert
@ -64,11 +65,11 @@ func (f *Forensics) SetCommittedQCs(headers []types.Header, incomingQC types.Quo
if i != 0 {
if decodedExtraField.QuorumCert.ProposedBlockInfo.Hash != headers[i-1].Hash() {
log.Error("[SetCommittedQCs] Headers shall be on the same chain and in the right order", "parentHash", h.ParentHash.Hex(), "headers[i-1].Hash()", headers[i-1].Hash().Hex())
return fmt.Errorf("headers shall be on the same chain and in the right order")
return errors.New("headers shall be on the same chain and in the right order")
} else if i == len(headers)-1 { // The last header shall be pointed by the incoming QC
if incomingQC.ProposedBlockInfo.Hash != h.Hash() {
log.Error("[SetCommittedQCs] incomingQc is not pointing at the last header received", "hash", h.Hash().Hex(), "incomingQC.ProposedBlockInfo.Hash", incomingQC.ProposedBlockInfo.Hash.Hex())
return fmt.Errorf("incomingQc is not pointing at the last header received")
return errors.New("incomingQc is not pointing at the last header received")
}
}
}
@ -91,7 +92,7 @@ func (f *Forensics) ProcessForensics(chain consensus.ChainReader, engine *XDPoS_
highestCommittedQCs := f.HighestCommittedQCs
if len(highestCommittedQCs) != NUM_OF_FORENSICS_QC {
log.Error("[ProcessForensics] HighestCommittedQCs value not set", "incomingQcProposedBlockHash", incomingQC.ProposedBlockInfo.Hash, "incomingQcProposedBlockNumber", incomingQC.ProposedBlockInfo.Number.Uint64(), "incomingQcProposedBlockRound", incomingQC.ProposedBlockInfo.Round)
return fmt.Errorf("HighestCommittedQCs value not set")
return errors.New("HighestCommittedQCs value not set")
}
// Find the QC1 and QC2. We only care 2 parents in front of the incomingQC. The returned value contains QC1, QC2 and QC3(the incomingQC)
incomingQuorunCerts, err := f.findAncestorQCs(chain, incomingQC, 2)
@ -163,7 +164,7 @@ func (f *Forensics) SendForensicProof(chain consensus.ChainReader, engine *XDPoS
if ancestorBlock == nil {
log.Error("[SendForensicProof] Unable to find the ancestor block by its hash", "Hash", ancestorHash)
return fmt.Errorf("Can't find ancestor block via hash")
return errors.New("Can't find ancestor block via hash")
}
content, err := json.Marshal(&types.ForensicsContent{
@ -209,7 +210,7 @@ func (f *Forensics) findAncestorQCs(chain consensus.ChainReader, currentQc types
parentHeader := chain.GetHeaderByHash(parentHash)
if parentHeader == nil {
log.Error("[findAncestorQCs] Forensics findAncestorQCs unable to find its parent block header", "BlockNum", parentHeader.Number.Int64(), "ParentHash", parentHash.Hex())
return nil, fmt.Errorf("unable to find parent block header in forensics")
return nil, errors.New("unable to find parent block header in forensics")
}
var decodedExtraField types.ExtraFields_v2
err := utils.DecodeBytesExtraFields(parentHeader.Extra, &decodedExtraField)
@ -318,7 +319,7 @@ func (f *Forensics) findAncestorQcThroughRound(chain consensus.ChainReader, high
}
ancestorQC = *decodedExtraField.QuorumCert
}
return ancestorQC, lowerRoundQCs, higherRoundQCs, fmt.Errorf("[findAncestorQcThroughRound] Could not find ancestor QC")
return ancestorQC, lowerRoundQCs, higherRoundQCs, errors.New("[findAncestorQcThroughRound] Could not find ancestor QC")
}
func (f *Forensics) FindAncestorBlockHash(chain consensus.ChainReader, firstBlockInfo *types.BlockInfo, secondBlockInfo *types.BlockInfo) (common.Hash, []string, []string, error) {
@ -398,7 +399,7 @@ func (f *Forensics) ProcessVoteEquivocation(chain consensus.ChainReader, engine
highestCommittedQCs := f.HighestCommittedQCs
if len(highestCommittedQCs) != NUM_OF_FORENSICS_QC {
log.Error("[ProcessVoteEquivocation] HighestCommittedQCs value not set", "incomingVoteProposedBlockHash", incomingVote.ProposedBlockInfo.Hash, "incomingVoteProposedBlockNumber", incomingVote.ProposedBlockInfo.Number.Uint64(), "incomingVoteProposedBlockRound", incomingVote.ProposedBlockInfo.Round)
return fmt.Errorf("HighestCommittedQCs value not set")
return errors.New("HighestCommittedQCs value not set")
}
if incomingVote.ProposedBlockInfo.Round < highestCommittedQCs[NUM_OF_FORENSICS_QC-1].ProposedBlockInfo.Round {
log.Debug("Received a too old vote in forensics", "vote", incomingVote)

View file

@ -64,7 +64,7 @@ func (s *SnapshotV2) GetMappedCandidates() map[common.Address]struct{} {
func (s *SnapshotV2) IsCandidates(address common.Address) bool {
for _, n := range s.NextEpochCandidates {
if n.String() == address.String() {
if n == address {
return true
}
}

View file

@ -1,6 +1,7 @@
package engine_v2
import (
"errors"
"fmt"
"strconv"
"strings"
@ -99,7 +100,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
}
if snap == nil || len(snap.NextEpochCandidates) == 0 {
log.Error("[verifyTC] Something wrong with the snapshot from gapNumber", "messageGapNumber", timeoutCert.GapNumber, "snapshot", snap)
return fmt.Errorf("empty master node lists from snapshot")
return errors.New("empty master node lists from snapshot")
}
signatures, duplicates := UniqueSignatures(timeoutCert.Signatures)
@ -145,7 +146,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
haveError = fmt.Errorf("error while verifying TC message signatures, %s", err)
} else {
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures))
haveError = fmt.Errorf("fail to verify TC due to signature mis-match")
haveError = errors.New("fail to verify TC due to signature mis-match")
}
}
mutex.Unlock() // Unlock after modifying haveError

View file

@ -1,6 +1,7 @@
package engine_v2
import (
"errors"
"fmt"
"github.com/XinFinOrg/XDPoSChain/accounts"
@ -105,7 +106,7 @@ func (x *XDPoS_v2) signSignature(signingHash common.Hash) (types.Signature, erro
func (x *XDPoS_v2) verifyMsgSignature(signedHashToBeVerified common.Hash, signature types.Signature, masternodes []common.Address) (bool, common.Address, error) {
var signerAddress common.Address
if len(masternodes) == 0 {
return false, signerAddress, fmt.Errorf("Empty masternode list detected when verifying message signatures")
return false, signerAddress, errors.New("Empty masternode list detected when verifying message signatures")
}
// Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(signedHashToBeVerified.Bytes(), signature)

View file

@ -1,6 +1,7 @@
package engine_v2
import (
"errors"
"fmt"
"math/big"
"strconv"
@ -78,7 +79,7 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
epochInfo, err := x.getEpochSwitchInfo(chain, chain.CurrentHeader(), chain.CurrentHeader().Hash())
if err != nil {
log.Error("[voteHandler] Error when getting epoch switch Info", "error", err)
return fmt.Errorf("Fail on voteHandler due to failure in getting epoch switch info")
return errors.New("Fail on voteHandler due to failure in getting epoch switch info")
}
certThreshold := x.config.V2.Config(uint64(voteMsg.ProposedBlockInfo.Round)).CertThreshold
@ -177,7 +178,7 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole
epochInfo, err := x.getEpochSwitchInfo(chain, chain.CurrentHeader(), chain.CurrentHeader().Hash())
if err != nil {
log.Error("[voteHandler] Error when getting epoch switch Info", "error", err)
return fmt.Errorf("Fail on voteHandler due to failure in getting epoch switch info")
return errors.New("Fail on voteHandler due to failure in getting epoch switch info")
}
// Skip and wait for the next vote to process again if valid votes is less than what we required

View file

@ -2,6 +2,7 @@ package utils
import (
"bytes"
"errors"
"fmt"
"reflect"
"sort"
@ -79,7 +80,7 @@ func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
func DecodeBytesExtraFields(b []byte, val interface{}) error {
if len(b) == 0 {
return fmt.Errorf("extra field is 0 length")
return errors.New("extra field is 0 length")
}
switch b[0] {
case 2:

View file

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"
"math/big"
"math/rand"
@ -144,11 +145,11 @@ func getCommonBackend(t *testing.T, chainConfig *params.ChainConfig) *backends.S
// create test backend with smart contract in it
contractBackend2 := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.HexToAddress(common.MasternodeVotingSMC): {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.MasternodeVotingSMCBinary: {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
}, 10000000, chainConfig)
return contractBackend2
@ -163,7 +164,7 @@ func transferTx(t *testing.T, to common.Address, transferAmount int64) *types.Tr
amount := big.NewInt(transferAmount)
nonce := uint64(1)
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
signedTX, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(chainID)), voterKey)
if err != nil {
t.Fatal(err)
}
@ -178,12 +179,12 @@ func voteTX(gasLimit uint64, nonce uint64, addr string) (*types.Transaction, err
amountInt := new(big.Int)
amount, ok := amountInt.SetString("60000", 10)
if !ok {
return nil, fmt.Errorf("big int init failed")
return nil, errors.New("big int init failed")
}
to := common.HexToAddress(common.MasternodeVotingSMC)
to := common.MasternodeVotingSMCBinary
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
signedTX, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(chainID)), voterKey)
if err != nil {
return nil, err
}
@ -213,7 +214,7 @@ func GetSnapshotSigner(bc *BlockChain, header *types.Header) (signersList, error
}
func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testing.T) masterNodes {
addr := common.HexToAddress(common.MasternodeVotingSMC)
addr := common.MasternodeVotingSMCBinary
validator, err := contractValidator.NewXDCValidator(addr, backend)
if err != nil {
t.Fatal(err)
@ -321,7 +322,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
// Sign all the things for v1 block use v1 sigHash function
sighash, err := signFn(accounts.Account{Address: signer}, blockchain.Engine().(*XDPoS.XDPoS).SigHash(header).Bytes())
if err != nil {
panic(fmt.Errorf("Error when sign last v1 block hash during test block creation"))
panic(errors.New("Error when sign last v1 block hash during test block creation"))
}
copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash)
}
@ -411,7 +412,7 @@ func createBlockFromHeader(bc *BlockChain, customHeader *types.Header, txs []*ty
// nonce := uint64(0)
// to := common.HexToAddress("xdc35658f7b2a9e7701e65e7a654659eb1c481d1dc5")
// tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
// signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), acc4Key)
// signedTX, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(chainID)), acc4Key)
// if err != nil {
// t.Fatal(err)
// }

View file

@ -5,6 +5,7 @@ import (
"context"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"math/big"
"math/rand"
@ -103,12 +104,12 @@ func voteTX(gasLimit uint64, nonce uint64, addr string) (*types.Transaction, err
amountInt := new(big.Int)
amount, ok := amountInt.SetString("60000", 10)
if !ok {
return nil, fmt.Errorf("big int init failed")
return nil, errors.New("big int init failed")
}
to := common.HexToAddress(common.MasternodeVotingSMC)
to := common.MasternodeVotingSMCBinary
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
signedTX, err := types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(chainID)), voterKey)
if err != nil {
return nil, err
}
@ -189,11 +190,11 @@ func getCommonBackend(t *testing.T, chainConfig *params.ChainConfig) *backends.S
// create test backend with smart contract in it
contractBackend2 := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.HexToAddress(common.MasternodeVotingSMC): {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.MasternodeVotingSMCBinary: {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
}, 10000000, chainConfig)
return contractBackend2
@ -273,19 +274,19 @@ func getMultiCandidatesBackend(t *testing.T, chainConfig *params.ChainConfig, n
// create test backend with smart contract in it
contractBackend2 := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.HexToAddress(common.MasternodeVotingSMC): {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
common.MasternodeVotingSMCBinary: {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
}, 10000000, chainConfig)
return contractBackend2
}
func signingTxWithKey(header *types.Header, nonce uint64, privateKey *ecdsa.PrivateKey) (*types.Transaction, error) {
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.HexToAddress(common.BlockSigners))
s := types.NewEIP155Signer(big.NewInt(chainID))
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.BlockSignersBinary)
s := types.LatestSignerForChainID(big.NewInt(chainID))
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], privateKey)
if err != nil {
@ -299,8 +300,8 @@ func signingTxWithKey(header *types.Header, nonce uint64, privateKey *ecdsa.Priv
}
func signingTxWithSignerFn(header *types.Header, nonce uint64, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) (*types.Transaction, error) {
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.HexToAddress(common.BlockSigners))
s := types.NewEIP155Signer(big.NewInt(chainID))
tx := contracts.CreateTxSign(header.Number, header.Hash(), nonce, common.BlockSignersBinary)
s := types.LatestSignerForChainID(big.NewInt(chainID))
h := s.Hash(tx)
sig, err := signFn(accounts.Account{Address: signer}, h[:])
if err != nil {
@ -335,7 +336,7 @@ func GetSnapshotSigner(bc *BlockChain, header *types.Header) (signersList, error
}
func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testing.T) masterNodes {
addr := common.HexToAddress(common.MasternodeVotingSMC)
addr := common.MasternodeVotingSMCBinary
validator, err := contractValidator.NewXDCValidator(addr, backend)
if err != nil {
t.Fatal(err)
@ -633,7 +634,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
// Sign all the things for v1 block use v1 sigHash function
sighash, err := signFn(accounts.Account{Address: signer}, blockchain.Engine().(*XDPoS.XDPoS).SigHash(header).Bytes())
if err != nil {
panic(fmt.Errorf("Error when sign last v1 block hash during test block creation"))
panic(errors.New("Error when sign last v1 block hash during test block creation"))
}
copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash)
}
@ -737,7 +738,7 @@ func findSignerAndSignFn(bc *BlockChain, header *types.Header, signer common.Add
var decodedExtraField types.ExtraFields_v2
err := utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
if err != nil {
panic(fmt.Errorf("fail to seal header for v2 block"))
panic(errors.New("fail to seal header for v2 block"))
}
round := decodedExtraField.Round
masterNodes := getMasternodesList(signer)
@ -757,7 +758,7 @@ func findSignerAndSignFn(bc *BlockChain, header *types.Header, signer common.Add
}
addressedSignFn = signFn
if err != nil {
panic(fmt.Errorf("Error trying to use one of the pre-defined private key to sign"))
panic(errors.New("Error trying to use one of the pre-defined private key to sign"))
}
}

View file

@ -18,6 +18,7 @@ package console
import (
"encoding/json"
"errors"
"fmt"
"io"
"reflect"
@ -75,18 +76,18 @@ func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) {
return nil, err
}
if password != confirm {
return nil, fmt.Errorf("passwords don't match!")
return nil, errors.New("passwords don't match!")
}
// A single string password was specified, use that
case len(call.Arguments) == 1 && call.Argument(0).ToString() != nil:
password = call.Argument(0).ToString().String()
default:
return nil, fmt.Errorf("expected 0 or 1 string argument")
return nil, errors.New("expected 0 or 1 string argument")
}
// Password acquired, execute the call and return
newAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("newAccount"))
if !callable {
return nil, fmt.Errorf("jeth.newAccount is not callable")
return nil, errors.New("jeth.newAccount is not callable")
}
ret, err := newAccount(goja.Null(), call.VM.ToValue(password))
if err != nil {
@ -100,7 +101,7 @@ func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) {
func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) {
// Make sure we have a wallet specified to open
if call.Argument(0).ToObject(call.VM).ClassName() != "String" {
return nil, fmt.Errorf("first argument must be the wallet URL to open")
return nil, errors.New("first argument must be the wallet URL to open")
}
wallet := call.Argument(0)
@ -113,7 +114,7 @@ func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) {
// Open the wallet and return if successful in itself
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, fmt.Errorf("jeth.openWallet is not callable")
return nil, errors.New("jeth.openWallet is not callable")
}
val, err := openWallet(goja.Null(), wallet, passwd)
if err == nil {
@ -147,7 +148,7 @@ func (b *bridge) readPassphraseAndReopenWallet(call jsre.Call) (goja.Value, erro
}
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, fmt.Errorf("jeth.openWallet is not callable")
return nil, errors.New("jeth.openWallet is not callable")
}
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
}
@ -168,7 +169,7 @@ func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) {
}
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, fmt.Errorf("jeth.openWallet is not callable")
return nil, errors.New("jeth.openWallet is not callable")
}
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
}
@ -180,7 +181,7 @@ func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) {
func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
// Make sure we have an account specified to unlock.
if call.Argument(0).ExportType().Kind() != reflect.String {
return nil, fmt.Errorf("first argument must be the account to unlock")
return nil, errors.New("first argument must be the account to unlock")
}
account := call.Argument(0)
@ -195,7 +196,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
passwd = call.VM.ToValue(input)
} else {
if call.Argument(1).ExportType().Kind() != reflect.String {
return nil, fmt.Errorf("password must be a string")
return nil, errors.New("password must be a string")
}
passwd = call.Argument(1)
}
@ -204,7 +205,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
duration := goja.Null()
if !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
if !isNumber(call.Argument(2)) {
return nil, fmt.Errorf("unlock duration must be a number")
return nil, errors.New("unlock duration must be a number")
}
duration = call.Argument(2)
}
@ -212,7 +213,7 @@ func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
// Send the request to the backend and return.
unlockAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("unlockAccount"))
if !callable {
return nil, fmt.Errorf("jeth.unlockAccount is not callable")
return nil, errors.New("jeth.unlockAccount is not callable")
}
return unlockAccount(goja.Null(), account, passwd, duration)
}
@ -228,10 +229,10 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) {
)
if message.ExportType().Kind() != reflect.String {
return nil, fmt.Errorf("first argument must be the message to sign")
return nil, errors.New("first argument must be the message to sign")
}
if account.ExportType().Kind() != reflect.String {
return nil, fmt.Errorf("second argument must be the account to sign with")
return nil, errors.New("second argument must be the account to sign with")
}
// if the password is not given or null ask the user and ensure password is a string
@ -243,13 +244,13 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) {
}
passwd = call.VM.ToValue(input)
} else if passwd.ExportType().Kind() != reflect.String {
return nil, fmt.Errorf("third argument must be the password to unlock the account")
return nil, errors.New("third argument must be the password to unlock the account")
}
// Send the request to the backend and return
sign, callable := goja.AssertFunction(getJeth(call.VM).Get("unlockAccount"))
if !callable {
return nil, fmt.Errorf("jeth.unlockAccount is not callable")
return nil, errors.New("jeth.unlockAccount is not callable")
}
return sign(goja.Null(), message, account, passwd)
}
@ -257,7 +258,7 @@ func (b *bridge) Sign(call jsre.Call) (goja.Value, error) {
// Sleep will block the console for the specified number of seconds.
func (b *bridge) Sleep(call jsre.Call) (goja.Value, error) {
if !isNumber(call.Argument(0)) {
return nil, fmt.Errorf("usage: sleep(<number of seconds>)")
return nil, errors.New("usage: sleep(<number of seconds>)")
}
sleep := call.Argument(0).ToFloat()
time.Sleep(time.Duration(sleep * float64(time.Second)))
@ -274,17 +275,17 @@ func (b *bridge) SleepBlocks(call jsre.Call) (goja.Value, error) {
)
nArgs := len(call.Arguments)
if nArgs == 0 {
return nil, fmt.Errorf("usage: sleepBlocks(<n blocks>[, max sleep in seconds])")
return nil, errors.New("usage: sleepBlocks(<n blocks>[, max sleep in seconds])")
}
if nArgs >= 1 {
if !isNumber(call.Argument(0)) {
return nil, fmt.Errorf("expected number as first argument")
return nil, errors.New("expected number as first argument")
}
blocks = call.Argument(0).ToInteger()
}
if nArgs >= 2 {
if isNumber(call.Argument(1)) {
return nil, fmt.Errorf("expected number as second argument")
return nil, errors.New("expected number as second argument")
}
sleep = call.Argument(1).ToInteger()
}
@ -361,7 +362,7 @@ func (b *bridge) Send(call jsre.Call) (goja.Value, error) {
JSON := call.VM.Get("JSON").ToObject(call.VM)
parse, callable := goja.AssertFunction(JSON.Get("parse"))
if !callable {
return nil, fmt.Errorf("JSON.parse is not a function")
return nil, errors.New("JSON.parse is not a function")
}
resultVal, err := parse(goja.Null(), call.VM.ToValue(string(result)))
if err != nil {

View file

@ -91,10 +91,13 @@ func TestFeeTxWithTRC21Token(t *testing.T) {
t.Fatal("check balance after fail transfer in tr20: ", err, "get", balance, "transfer", airDropAmount)
}
//check balance fee
// check balance fee
balanceIssuerFee, err = trc21Issuer.GetTokenCapacity(trc21TokenAddr)
if err != nil || balanceIssuerFee.Cmp(remainFee) != 0 {
t.Fatal("can't get balance token fee in smart contract: ", err, "got", balanceIssuerFee, "wanted", remainFee)
if err != nil {
t.Fatal("can't get balance token fee in smart contract: ", err)
}
if balanceIssuerFee.Cmp(remainFee) != 0 {
t.Fatal("check balance token fee in smart contract: got", balanceIssuerFee, "wanted", remainFee)
}
//check trc21 SMC balance
balance, err = contractBackend.BalanceAt(nil, trc21IssuerAddr, nil)

View file

@ -87,7 +87,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m
// Create and send tx to smart contract for sign validate block.
nonce := pool.Nonce(account.Address)
tx := CreateTxSign(block.Number(), block.Hash(), nonce, common.HexToAddress(common.BlockSigners))
tx := CreateTxSign(block.Number(), block.Hash(), nonce, common.BlockSignersBinary)
txSigned, err := wallet.SignTx(account, tx, chainConfig.ChainId)
if err != nil {
log.Error("Fail to create tx sign", "error", err)
@ -112,7 +112,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m
// Only process when private key empty in state db.
// Save randomize key into state db.
randomizeKeyValue := RandStringByte(32)
tx, err := BuildTxSecretRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), chainConfig.XDPoS.Epoch, randomizeKeyValue)
tx, err := BuildTxSecretRandomize(nonce+1, common.RandomizeSMCBinary, chainConfig.XDPoS.Epoch, randomizeKeyValue)
if err != nil {
log.Error("Fail to get tx opening for randomize", "error", err)
return err
@ -141,7 +141,7 @@ func CreateTransactionSign(chainConfig *params.ChainConfig, pool *core.TxPool, m
return err
}
tx, err := BuildTxOpeningRandomize(nonce+1, common.HexToAddress(common.RandomizeSMC), randomizeKeyValue)
tx, err := BuildTxOpeningRandomize(nonce+1, common.RandomizeSMCBinary, randomizeKeyValue)
if err != nil {
log.Error("Fail to get tx opening for randomize", "error", err)
return err
@ -232,7 +232,7 @@ func GetSignersByExecutingEVM(addrBlockSigner common.Address, client bind.Contra
// Get random from randomize contract.
func GetRandomizeFromContract(client bind.ContractBackend, addrMasternode common.Address) (int64, error) {
randomize, err := randomizeContract.NewXDCRandomize(common.HexToAddress(common.RandomizeSMC), client)
randomize, err := randomizeContract.NewXDCRandomize(common.RandomizeSMCBinary, client)
if err != nil {
log.Error("Fail to get instance of randomize", "error", err)
}

View file

@ -150,7 +150,7 @@ func TestRewardBalance(t *testing.T) {
logCaps[i] = &logCap{accounts[randIndex].From.String(), randCap}
}
foundationAddr := common.HexToAddress(common.FoudationAddr)
foundationAddr := common.FoudationAddrBinary
totalReward := new(big.Int).SetInt64(15 * 1000)
rewards, err := GetRewardBalancesRate(foundationAddr, acc3Addr, totalReward, baseValidator)
if err != nil {
@ -309,13 +309,13 @@ func TestStatedbUtils(t *testing.T) {
return true
}
contractBackend.ForEachStorageAt(ctx, validatorAddress, nil, f)
genesisAlloc[common.HexToAddress(common.MasternodeVotingSMC)] = core.GenesisAccount{
genesisAlloc[common.MasternodeVotingSMCBinary] = core.GenesisAccount{
Balance: validatorCap,
Code: code,
Storage: storage,
}
contractBackendForValidator := backends.NewXDCSimulatedBackend(genesisAlloc, 10000000, params.TestXDPoSMockChainConfig)
validator, err := NewValidator(transactOpts, common.HexToAddress(common.MasternodeVotingSMC), contractBackendForValidator)
validator, err := NewValidator(transactOpts, common.MasternodeVotingSMCBinary, contractBackendForValidator)
if err != nil {
t.Fatalf("can't get validator object: %v", err)
}
@ -379,4 +379,4 @@ func TestStatedbUtils(t *testing.T) {
t.Fatalf("cap should not be zero")
}
}
}
}

View file

@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, false, false)
gas, _ := IntrinsicGas(data, nil, false, false)
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
gen.AddTx(tx)
}

View file

@ -17,6 +17,7 @@
package core
import (
"errors"
"fmt"
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
@ -113,7 +114,7 @@ func (v *BlockValidator) ValidateTradingOrder(statedb *state.StateDB, XDCxStated
}
XDCXService := XDPoSEngine.GetXDCXService()
if XDCXService == nil {
return fmt.Errorf("XDCx not found")
return errors.New("XDCx not found")
}
log.Debug("verify matching transaction found a TxMatches Batch", "numTxMatches", len(txMatchBatch.Data))
tradingResult := map[common.Hash]tradingstate.MatchingResult{}
@ -149,11 +150,11 @@ func (v *BlockValidator) ValidateLendingOrder(statedb *state.StateDB, lendingSta
}
XDCXService := XDPoSEngine.GetXDCXService()
if XDCXService == nil {
return fmt.Errorf("XDCx not found")
return errors.New("XDCx not found")
}
lendingService := XDPoSEngine.GetLendingService()
if lendingService == nil {
return fmt.Errorf("lendingService not found")
return errors.New("lendingService not found")
}
log.Debug("verify lendingItem ", "numItems", len(batch.Data))
lendingResult := map[common.Hash]lendingstate.MatchingResult{}

View file

@ -58,6 +58,11 @@ var (
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
CheckpointCh = make(chan int)
ErrNoGenesis = errors.New("Genesis not found in chain")
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
blockReorgDropMeter = metrics.NewRegisteredMeter("chain/reorg/drop", nil)
blockReorgInvalidatedTx = metrics.NewRegisteredMeter("chain/reorg/invalidTx", nil)
)
const (
@ -252,6 +257,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
return bc, nil
}
// GetVMConfig returns the block chain VM config.
func (bc *BlockChain) GetVMConfig() *vm.Config {
return &bc.vmConfig
}
// NewBlockChainEx extend old blockchain, add order state db
func NewBlockChainEx(db ethdb.Database, XDCxDb ethdb.XDCxDatabase, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) {
blockchain, err := NewBlockChain(db, cacheConfig, chainConfig, engine, vmConfig)
@ -2187,10 +2197,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
}
if oldBlock == nil {
return fmt.Errorf("Invalid old chain")
return errors.New("Invalid old chain")
}
if newBlock == nil {
return fmt.Errorf("Invalid new chain")
return errors.New("Invalid new chain")
}
for {
@ -2206,10 +2216,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
oldBlock, newBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1), bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1)
if oldBlock == nil {
return fmt.Errorf("Invalid old chain")
return errors.New("Invalid old chain")
}
if newBlock == nil {
return fmt.Errorf("Invalid new chain")
return errors.New("Invalid new chain")
}
}
// Ensure XDPoS engine committed block will be not reverted
@ -2245,6 +2255,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
}
logFn("Chain split detected", "number", commonBlock.Number(), "hash", commonBlock.Hash(),
"drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
blockReorgAddMeter.Mark(int64(len(newChain)))
blockReorgDropMeter.Mark(int64(len(oldChain)))
blockReorgMeter.Mark(1)
} else {
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash())
}
@ -2549,7 +2562,7 @@ func (bc *BlockChain) UpdateM1() error {
if err != nil {
return err
}
addr := common.HexToAddress(common.MasternodeVotingSMC)
addr := common.MasternodeVotingSMCBinary
validator, err := contractValidator.NewXDCValidator(addr, client)
if err != nil {
return err

View file

@ -561,7 +561,7 @@ func TestFastVsFullChains(t *testing.T) {
Alloc: GenesisAlloc{address: {Balance: funds}},
}
genesis = gspec.MustCommit(gendb)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.LatestSigner(gspec.Config)
)
blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00})
@ -736,7 +736,7 @@ func TestChainTxReorgs(t *testing.T) {
},
}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.LatestSigner(gspec.Config)
)
// Create two transactions shared between the chains:
@ -842,7 +842,7 @@ func TestLogReorgs(t *testing.T) {
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.LatestSigner(gspec.Config)
)
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -889,7 +889,7 @@ func TestLogReorgs(t *testing.T) {
// Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
// }
// genesis = gspec.MustCommit(db)
// signer = types.NewEIP155Signer(gspec.Config.ChainId)
// signer = types.LatestSigner(gspec.Config)
// )
//
// blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
@ -1015,7 +1015,7 @@ func TestEIP155Transition(t *testing.T) {
funds = big.NewInt(1000000000)
deleteAddr = common.Address{1}
gspec = &Genesis{
Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
}
genesis = gspec.MustCommit(db)
@ -1046,7 +1046,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
tx, err = basicTx(types.LatestSigner(gspec.Config))
if err != nil {
t.Fatal(err)
}
@ -1058,7 +1058,7 @@ func TestEIP155Transition(t *testing.T) {
}
block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
tx, err = basicTx(types.LatestSigner(gspec.Config))
if err != nil {
t.Fatal(err)
}
@ -1086,7 +1086,7 @@ func TestEIP155Transition(t *testing.T) {
}
// generate an invalid chain id transaction
config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
config := &params.ChainConfig{ChainId: big.NewInt(2), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
@ -1095,9 +1095,8 @@ func TestEIP155Transition(t *testing.T) {
return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key)
}
)
switch i {
case 0:
tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
if i == 0 {
tx, err = basicTx(types.LatestSigner(config))
if err != nil {
t.Fatal(err)
}
@ -1136,7 +1135,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
var (
tx *types.Transaction
err error
signer = types.NewEIP155Signer(gspec.Config.ChainId)
signer = types.LatestSigner(gspec.Config)
)
switch i {
case 0:
@ -1167,7 +1166,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
t.Error("account should not exist")
}
// account musn't be created post eip 161
// account mustn't be created post eip 161
if _, err := blockchain.InsertChain(types.Blocks{blocks[2]}); err != nil {
t.Fatal(err)
}
@ -1412,3 +1411,93 @@ func TestAreTwoBlocksSamePath(t *testing.T) {
})
}
// TestEIP2718Transition tests that an EIP-2718 transaction will be accepted
// after the fork block has passed. This is verified by sending an EIP-2930
// access list transaction, which specifies a single slot access, and then
// checking that the gas usage of a hot SLOAD and a cold SLOAD are calculated
// correctly.
func TestEIP2718Transition(t *testing.T) {
var (
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
// Generate a canonical chain to act as the main dataset
engine = ethash.NewFaker()
db = rawdb.NewMemoryDatabase()
// A sender who makes transactions, has some funds
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
gspec = &Genesis{
Config: &params.ChainConfig{
ChainId: new(big.Int).SetBytes([]byte("eip1559")),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
Eip1559Block: big.NewInt(0),
},
Alloc: GenesisAlloc{
address: {Balance: funds},
// The address 0xAAAA sloads 0x00 and 0x01
aa: {
Code: []byte{
byte(vm.PC),
byte(vm.PC),
byte(vm.SLOAD),
byte(vm.SLOAD),
},
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
genesis = gspec.MustCommit(db)
)
blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})
// One transaction to 0xAAAA
signer := types.LatestSigner(gspec.Config)
tx, _ := types.SignNewTx(key, signer, &types.AccessListTx{
ChainID: gspec.Config.ChainId,
Nonce: 0,
To: &aa,
Gas: 30000,
GasPrice: big.NewInt(1),
AccessList: types.AccessList{{
Address: aa,
StorageKeys: []common.Hash{{0}},
}},
})
b.AddTx(tx)
})
// Import the canonical chain
diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{})
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
block := chain.GetBlockByNumber(1)
// Expected gas is intrinsic + 2 * pc + hot load + cold load, since only one load is in the access list
expected := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas + vm.GasQuickStep*2 + vm.WarmStorageReadCostEIP2929 + vm.ColdSloadCostEIP2929
if block.GasUsed() != expected {
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed())
}
}

View file

@ -18,6 +18,7 @@ package core
import (
"encoding/binary"
"errors"
"fmt"
"sync"
"sync/atomic"
@ -357,7 +358,7 @@ func (c *ChainIndexer) processSection(section uint64, lastHead common.Hash) (com
if header == nil {
return common.Hash{}, fmt.Errorf("block #%d [%x…] not found", number, hash[:4])
} else if header.ParentHash != lastHead {
return common.Hash{}, fmt.Errorf("chain reorged during section processing")
return common.Hash{}, errors.New("chain reorged during section processing")
}
c.backend.Process(header)
lastHead = header.Hash()

View file

@ -18,11 +18,11 @@ package core
import (
"bytes"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/rlp"
@ -335,6 +335,10 @@ func TestLookupStorage(t *testing.T) {
func TestBlockReceiptStorage(t *testing.T) {
db := rawdb.NewMemoryDatabase()
// Create a live block since we need metadata to reconstruct the receipt
tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil)
receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed,
CumulativeGasUsed: 1,
@ -342,10 +346,12 @@ func TestBlockReceiptStorage(t *testing.T) {
{Address: common.BytesToAddress([]byte{0x11})},
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
},
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
TxHash: tx1.Hash(),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
GasUsed: 111111,
}
receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1})
receipt2 := &types.Receipt{
PostState: common.Hash{2}.Bytes(),
CumulativeGasUsed: 2,
@ -353,10 +359,12 @@ func TestBlockReceiptStorage(t *testing.T) {
{Address: common.BytesToAddress([]byte{0x22})},
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
},
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
TxHash: tx2.Hash(),
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
GasUsed: 222222,
}
receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2})
receipts := []*types.Receipt{receipt1, receipt2}
// Check that no receipt entries are in a pristine database

View file

@ -16,7 +16,11 @@
package core
import "errors"
import (
"errors"
"github.com/XinFinOrg/XDPoSChain/core/types"
)
var (
// ErrKnownBlock is returned when a block to import is already known locally.
@ -38,4 +42,8 @@ var (
ErrNotFoundM1 = errors.New("list M1 not found ")
ErrStopPreparingBlock = errors.New("stop calculating a block not verified by M2")
// ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration.
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported
)

View file

@ -141,10 +141,10 @@ func (e *GenesisMismatchError) Error() string {
// SetupGenesisBlock writes or updates the genesis block in db.
// The block that will be used is:
//
// genesis == nil genesis != nil
// +------------------------------------------
// db has no genesis | main-net default | genesis
// db has genesis | from DB | genesis (if compatible)
// genesis == nil genesis != nil
// +------------------------------------------
// db has no genesis | main-net default | genesis
// db has genesis | from DB | genesis (if compatible)
//
// The stored chain configuration will be updated if it is compatible (i.e. does not
// specify a fork block below the local head block). In case of a conflict, the
@ -200,7 +200,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
// are returned to the caller unless we're already at block zero.
height := GetBlockNumber(db, GetHeadHeaderHash(db))
if height == missingNumber {
return newcfg, stored, fmt.Errorf("missing block number for head header hash")
return newcfg, stored, errors.New("missing block number for head header hash")
}
compatErr := storedcfg.CheckCompatible(newcfg, height)
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
@ -275,7 +275,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
block := g.ToBlock(db)
if block.Number().Sign() != 0 {
return nil, fmt.Errorf("can't commit genesis block with number > 0")
return nil, errors.New("can't commit genesis block with number > 0")
}
if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil {
return nil, err

View file

@ -435,7 +435,7 @@ func (pool *LendingPool) validateNewLending(cloneStateDb *state.StateDB, cloneLe
validCollateral := false
collateralList := lendingstate.GetCollaterals(cloneStateDb, tx.RelayerAddress(), tx.LendingToken(), tx.Term())
for _, collateral := range collateralList {
if tx.CollateralToken().String() == collateral.String() {
if tx.CollateralToken() == collateral {
validCollateral = true
break
}
@ -476,10 +476,10 @@ func (pool *LendingPool) validateRepayLending(cloneStateDb *state.StateDB, clone
if lendingTrade == lendingstate.EmptyLendingTrade {
return ErrInvalidLendingTradeID
}
if tx.UserAddress().String() != lendingTrade.Borrower.String() {
if tx.UserAddress() != lendingTrade.Borrower {
return ErrInvalidLendingUserAddress
}
if tx.RelayerAddress().String() != lendingTrade.BorrowingRelayer.String() {
if tx.RelayerAddress() != lendingTrade.BorrowingRelayer {
return ErrInvalidLendingRelayer
}
if err := pool.validateBalance(cloneStateDb, cloneLendingStateDb, tx, tx.CollateralToken()); err != nil {
@ -499,10 +499,10 @@ func (pool *LendingPool) validateTopupLending(cloneStateDb *state.StateDB, clone
if lendingTrade == lendingstate.EmptyLendingTrade {
return ErrInvalidLendingTradeID
}
if tx.UserAddress().String() != lendingTrade.Borrower.String() {
if tx.UserAddress() != lendingTrade.Borrower {
return ErrInvalidLendingUserAddress
}
if tx.RelayerAddress().String() != lendingTrade.BorrowingRelayer.String() {
if tx.RelayerAddress() != lendingTrade.BorrowingRelayer {
return ErrInvalidLendingRelayer
}
if err := pool.validateBalance(cloneStateDb, cloneLendingStateDb, tx, lendingTrade.CollateralToken); err != nil {
@ -519,7 +519,7 @@ func (pool *LendingPool) validateBalance(cloneStateDb *state.StateDB, cloneLendi
XDCXServ := XDPoSEngine.GetXDCXService()
lendingServ := XDPoSEngine.GetLendingService()
if XDCXServ == nil {
return fmt.Errorf("XDCx not found in order validation")
return errors.New("XDCx not found in order validation")
}
lendingTokenDecimal, err := XDCXServ.GetTokenDecimal(pool.chain, cloneStateDb, tx.LendingToken())
if err != nil {
@ -554,10 +554,10 @@ func (pool *LendingPool) validateBalance(cloneStateDb *state.StateDB, cloneLendi
}
}
if lendTokenXDCPrice == nil || lendTokenXDCPrice.Sign() == 0 {
if tx.LendingToken().String() == common.XDCNativeAddress {
if tx.LendingToken() == common.XDCNativeAddressBinary {
lendTokenXDCPrice = common.BasePrice
} else {
lendTokenXDCPrice, err = lendingServ.GetMediumTradePriceBeforeEpoch(pool.chain, cloneStateDb, cloneTradingStateDb, tx.LendingToken(), common.HexToAddress(common.XDCNativeAddress))
lendTokenXDCPrice, err = lendingServ.GetMediumTradePriceBeforeEpoch(pool.chain, cloneStateDb, cloneTradingStateDb, tx.LendingToken(), common.XDCNativeAddressBinary)
if err != nil {
return err
}

View file

@ -3,6 +3,13 @@ package core
import (
"context"
"fmt"
"log"
"math/big"
"strconv"
"strings"
"testing"
"time"
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
@ -10,12 +17,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/ethclient"
"github.com/XinFinOrg/XDPoSChain/rpc"
"log"
"math/big"
"strconv"
"strings"
"testing"
"time"
)
type LendingMsg struct {
@ -197,7 +198,7 @@ func TestSendLending(t *testing.T) {
testSendLending(key, nonce, USDAddress, common.Address{}, new(big.Int).Mul(_1E8, big.NewInt(1000)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
testSendLending(key, nonce, USDAddress, common.HexToAddress(common.XDCNativeAddress), new(big.Int).Mul(_1E8, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, USDAddress, common.XDCNativeAddressBinary, new(big.Int).Mul(_1E8, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
@ -206,7 +207,7 @@ func TestSendLending(t *testing.T) {
testSendLending(key, nonce, BTCAddress, common.Address{}, new(big.Int).Mul(_1E18, big.NewInt(1)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
testSendLending(key, nonce, BTCAddress, common.HexToAddress(common.XDCNativeAddress), new(big.Int).Mul(_1E18, big.NewInt(1)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, BTCAddress, common.XDCNativeAddressBinary, new(big.Int).Mul(_1E18, big.NewInt(1)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
@ -221,19 +222,19 @@ func TestSendLending(t *testing.T) {
// lendToken: XDC, collateral: BTC
// amount 1000 XDC
testSendLending(key, nonce, common.HexToAddress(common.XDCNativeAddress), common.Address{}, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, common.XDCNativeAddressBinary, common.Address{}, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
testSendLending(key, nonce, common.HexToAddress(common.XDCNativeAddress), BTCAddress, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, common.XDCNativeAddressBinary, BTCAddress, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
// lendToken: XDC, collateral: ETH
// amount 1000 XDC
testSendLending(key, nonce, common.HexToAddress(common.XDCNativeAddress), common.Address{}, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, common.XDCNativeAddressBinary, common.Address{}, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Investing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
testSendLending(key, nonce, common.HexToAddress(common.XDCNativeAddress), ETHAddress, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, common.XDCNativeAddressBinary, ETHAddress, new(big.Int).Mul(_1E18, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
nonce++
time.Sleep(time.Second)
}
@ -282,6 +283,6 @@ func TestRecallLending(t *testing.T) {
t.Error("fail to get nonce")
t.FailNow()
}
testSendLending(key, nonce, USDAddress, common.HexToAddress(common.XDCNativeAddress), new(big.Int).Mul(_1E8, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
testSendLending(key, nonce, USDAddress, common.XDCNativeAddressBinary, new(big.Int).Mul(_1E8, big.NewInt(1000)), interestRate, lendingstate.Borrowing, lendingstate.LendingStatusNew, true, 0, 0, common.Hash{}, "")
time.Sleep(2 * time.Second)
}

View file

@ -468,7 +468,7 @@ func (pool *OrderPool) validateOrder(tx *types.OrderTransaction) error {
}
XDCXServ := XDPoSEngine.GetXDCXService()
if XDCXServ == nil {
return fmt.Errorf("XDCx not found in order validation")
return errors.New("XDCx not found in order validation")
}
baseDecimal, err := XDCXServ.GetTokenDecimal(pool.chain, cloneStateDb, tx.BaseToken())
if err != nil {

View file

@ -2,17 +2,18 @@ package core
import (
"context"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/ethclient"
"github.com/XinFinOrg/XDPoSChain/rpc"
"log"
"math/big"
"strconv"
"strings"
"testing"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/ethclient"
"github.com/XinFinOrg/XDPoSChain/rpc"
)
type OrderMsg struct {
@ -89,7 +90,7 @@ func testSendOrder(t *testing.T, amount, price *big.Int, side string, status str
Price: price,
ExchangeAddress: common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"),
UserAddress: crypto.PubkeyToAddress(privateKey.PublicKey),
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: BTCAddress,
Status: status,
Side: side,
@ -124,7 +125,7 @@ func testSendOrderXDCUSD(t *testing.T, amount, price *big.Int, side string, stat
Price: price,
ExchangeAddress: common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"),
UserAddress: crypto.PubkeyToAddress(privateKey.PublicKey),
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: USDAddress,
Status: status,
Side: side,
@ -194,7 +195,7 @@ func testSendOrderXDCBTC(t *testing.T, amount, price *big.Int, side string, stat
Price: price,
ExchangeAddress: common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"),
UserAddress: crypto.PubkeyToAddress(privateKey.PublicKey),
BaseToken: common.HexToAddress(common.XDCNativeAddress),
BaseToken: common.XDCNativeAddressBinary,
QuoteToken: BTCAddress,
Status: status,
Side: side,

View file

@ -730,6 +730,32 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
return root, err
}
// PrepareAccessList handles the preparatory steps for executing a state transition with
// regards to both EIP-2929 and EIP-2930:
//
// - Add sender to access list (2929)
// - Add destination to access list (2929)
// - Add precompiles to access list (2929)
// - Add the contents of the optional tx access list (2930)
//
// This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
s.AddAddressToAccessList(sender)
if dst != nil {
s.AddAddressToAccessList(*dst)
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range precompiles {
s.AddAddressToAccessList(addr)
}
for _, el := range list {
s.AddAddressToAccessList(el.Address)
for _, key := range el.StorageKeys {
s.AddSlotToAccessList(el.Address, key)
}
}
}
// AddAddressToAccessList adds the given address to the access list
func (s *StateDB) AddAddressToAccessList(addr common.Address) {
if s.accessList.AddAddress(addr) {
@ -770,6 +796,6 @@ func (s *StateDB) GetOwner(candidate common.Address) common.Address {
// validatorsState[_candidate].owner;
locValidatorsState := GetLocMappingAtKey(candidate.Hash(), slot)
locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0)))
ret := s.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateOwner))
ret := s.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locCandidateOwner))
return common.HexToAddress(ret.Hex())
}

View file

@ -20,7 +20,7 @@ func GetSigners(statedb *StateDB, block *types.Block) []common.Address {
slot := slotBlockSignerMapping["blockSigners"]
keys := []common.Hash{}
keyArrSlot := GetLocMappingAtKey(block.Hash(), slot)
arrSlot := statedb.GetState(common.HexToAddress(common.BlockSigners), common.BigToHash(keyArrSlot))
arrSlot := statedb.GetState(common.BlockSignersBinary, common.BigToHash(keyArrSlot))
arrLength := arrSlot.Big().Uint64()
for i := uint64(0); i < arrLength; i++ {
key := GetLocDynamicArrAtElement(common.BigToHash(keyArrSlot), i, 1)
@ -28,7 +28,7 @@ func GetSigners(statedb *StateDB, block *types.Block) []common.Address {
}
rets := []common.Address{}
for _, key := range keys {
ret := statedb.GetState(common.HexToAddress(common.BlockSigners), key)
ret := statedb.GetState(common.BlockSignersBinary, key)
rets = append(rets, common.HexToAddress(ret.Hex()))
}
@ -45,7 +45,7 @@ var (
func GetSecret(statedb *StateDB, address common.Address) [][32]byte {
slot := slotRandomizeMapping["randomSecret"]
locSecret := GetLocMappingAtKey(address.Hash(), slot)
arrLength := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locSecret))
arrLength := statedb.GetState(common.RandomizeSMCBinary, common.BigToHash(locSecret))
keys := []common.Hash{}
for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
key := GetLocDynamicArrAtElement(common.BigToHash(locSecret), i, 1)
@ -53,7 +53,7 @@ func GetSecret(statedb *StateDB, address common.Address) [][32]byte {
}
rets := [][32]byte{}
for _, key := range keys {
ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), key)
ret := statedb.GetState(common.RandomizeSMCBinary, key)
rets = append(rets, ret)
}
return rets
@ -62,7 +62,7 @@ func GetSecret(statedb *StateDB, address common.Address) [][32]byte {
func GetOpening(statedb *StateDB, address common.Address) [32]byte {
slot := slotRandomizeMapping["randomOpening"]
locOpening := GetLocMappingAtKey(address.Hash(), slot)
ret := statedb.GetState(common.HexToAddress(common.RandomizeSMC), common.BigToHash(locOpening))
ret := statedb.GetState(common.RandomizeSMCBinary, common.BigToHash(locOpening))
return ret
}
@ -92,13 +92,13 @@ var (
func GetCandidates(statedb *StateDB) []common.Address {
slot := slotValidatorMapping["candidates"]
slotHash := common.BigToHash(new(big.Int).SetUint64(slot))
arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), slotHash)
arrLength := statedb.GetState(common.MasternodeVotingSMCBinary, slotHash)
count := arrLength.Big().Uint64()
rets := make([]common.Address, 0, count)
for i := uint64(0); i < count; i++ {
key := GetLocDynamicArrAtElement(slotHash, i, 1)
ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key)
ret := statedb.GetState(common.MasternodeVotingSMCBinary, key)
if !ret.IsZero() {
rets = append(rets, common.HexToAddress(ret.Hex()))
}
@ -112,7 +112,7 @@ func GetCandidateOwner(statedb *StateDB, candidate common.Address) common.Addres
// validatorsState[_candidate].owner;
locValidatorsState := GetLocMappingAtKey(candidate.Hash(), slot)
locCandidateOwner := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(0)))
ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateOwner))
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locCandidateOwner))
return common.HexToAddress(ret.Hex())
}
@ -121,7 +121,7 @@ func GetCandidateCap(statedb *StateDB, candidate common.Address) *big.Int {
// validatorsState[_candidate].cap;
locValidatorsState := GetLocMappingAtKey(candidate.Hash(), slot)
locCandidateCap := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(1)))
ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locCandidateCap))
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locCandidateCap))
return ret.Big()
}
@ -129,7 +129,7 @@ func GetVoters(statedb *StateDB, candidate common.Address) []common.Address {
//mapping(address => address[]) voters;
slot := slotValidatorMapping["voters"]
locVoters := GetLocMappingAtKey(candidate.Hash(), slot)
arrLength := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BigToHash(locVoters))
arrLength := statedb.GetState(common.MasternodeVotingSMCBinary, common.BigToHash(locVoters))
keys := []common.Hash{}
for i := uint64(0); i < arrLength.Big().Uint64(); i++ {
key := GetLocDynamicArrAtElement(common.BigToHash(locVoters), i, 1)
@ -137,7 +137,7 @@ func GetVoters(statedb *StateDB, candidate common.Address) []common.Address {
}
rets := []common.Address{}
for _, key := range keys {
ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), key)
ret := statedb.GetState(common.MasternodeVotingSMCBinary, key)
rets = append(rets, common.HexToAddress(ret.Hex()))
}
@ -149,6 +149,6 @@ func GetVoterCap(statedb *StateDB, candidate, voter common.Address) *big.Int {
locValidatorsState := GetLocMappingAtKey(candidate.Hash(), slot)
locCandidateVoters := locValidatorsState.Add(locValidatorsState, new(big.Int).SetUint64(uint64(2)))
retByte := crypto.Keccak256(voter.Hash().Bytes(), common.BigToHash(locCandidateVoters).Bytes())
ret := statedb.GetState(common.HexToAddress(common.MasternodeVotingSMC), common.BytesToHash(retByte))
ret := statedb.GetState(common.MasternodeVotingSMCBinary, common.BytesToHash(retByte))
return ret.Big()
}

View file

@ -80,7 +80,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
misc.ApplyDAOHardFork(statedb)
}
if common.TIPSigning.Cmp(header.Number) == 0 {
statedb.DeleteAddress(common.HexToAddress(common.BlockSigners))
statedb.DeleteAddress(common.BlockSignersBinary)
}
parentState := statedb.Copy()
InitSignerInTransactions(p.config, header, block.Transactions())
@ -146,7 +146,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
misc.ApplyDAOHardFork(statedb)
}
if common.TIPSigning.Cmp(header.Number) == 0 {
statedb.DeleteAddress(common.HexToAddress(common.BlockSigners))
statedb.DeleteAddress(common.BlockSignersBinary)
}
if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock
@ -215,13 +215,14 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error, bool) {
if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPSigning(header.Number) {
to := tx.To()
if to != nil && *to == common.BlockSignersBinary && config.IsTIPSigning(header.Number) {
return ApplySignTransaction(config, statedb, header, tx, usedGas)
}
if tx.To() != nil && tx.To().String() == common.TradingStateAddr && config.IsTIPXDCXReceiver(header.Number) {
if to != nil && *to == common.TradingStateAddrBinary && config.IsTIPXDCXReceiver(header.Number) {
return ApplyEmptyTransaction(config, statedb, header, tx, usedGas)
}
if tx.To() != nil && tx.To().String() == common.XDCXLendingAddress && config.IsTIPXDCXReceiver(header.Number) {
if to != nil && *to == common.XDCXLendingAddressBinary && config.IsTIPXDCXReceiver(header.Number) {
return ApplyEmptyTransaction(config, statedb, header, tx, usedGas)
}
if tx.IsTradingTransaction() && config.IsTIPXDCXReceiver(header.Number) {
@ -233,8 +234,8 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
}
var balanceFee *big.Int
if tx.To() != nil {
if value, ok := tokensFee[*tx.To()]; ok {
if to != nil {
if value, ok := tokensFee[*to]; ok {
balanceFee = value
}
}
@ -242,23 +243,12 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
if err != nil {
return nil, 0, err, false
}
// Create a new context to be used in the EVM environment
// Create a new context to be used in the EVM environment.
context := NewEVMContext(msg, header, bc, author)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, XDCxState, config, cfg)
if config.IsEIP1559(header.Number) {
statedb.AddAddressToAccessList(msg.From())
if dst := msg.To(); dst != nil {
statedb.AddAddressToAccessList(*dst)
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range vmenv.ActivePrecompiles() {
statedb.AddAddressToAccessList(addr)
}
}
// If we don't have an explicit author (i.e. not mining), extract from the header
var beneficiary common.Address
if author == nil {
@ -419,7 +409,8 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
if err != nil {
return nil, 0, err, false
}
// Update the state with pending changes
// Update the state with pending changes.
var root []byte
if config.IsByzantium(header.Number) {
statedb.Finalise(true)
@ -428,23 +419,30 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
}
*usedGas += gas
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
// based on the eip phase, we're passing wether the root touch-delete accounts.
receipt := types.NewReceipt(root, failed, *usedGas)
// Create a new receipt for the transaction, storing the intermediate root and gas used
// by the tx.
receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
if failed {
receipt.Status = types.ReceiptStatusFailed
} else {
receipt.Status = types.ReceiptStatusSuccessful
}
receipt.TxHash = tx.Hash()
receipt.GasUsed = gas
// if the transaction created a contract, store the creation address in the receipt.
// If the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
}
// Set the receipt logs and create a bloom for filtering
// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
receipt.BlockHash = statedb.BlockHash()
receipt.BlockNumber = header.Number
receipt.TransactionIndex = uint(statedb.TxIndex())
if balanceFee != nil && failed {
state.PayFeeWithTRC21TxFail(statedb, msg.From(), *tx.To())
state.PayFeeWithTRC21TxFail(statedb, msg.From(), *to)
}
return receipt, gas, err, balanceFee != nil
}
@ -476,7 +474,7 @@ func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, he
// if the transaction created a contract, store the creation address in the receipt.
// Set the receipt logs and create a bloom for filtering
log := &types.Log{}
log.Address = common.HexToAddress(common.BlockSigners)
log.Address = common.BlockSignersBinary
log.BlockNumber = header.Number.Uint64()
statedb.AddLog(log)
receipt.Logs = statedb.GetLogs(tx.Hash())
@ -532,7 +530,6 @@ func InitSignerInTransactions(config *params.ChainConfig, header *types.Header,
go func(from int, to int) {
for j := from; j < to; j++ {
types.CacheSigner(signer, txs[j])
txs[j].CacheHash()
}
wg.Done()
}(from, to)

View file

@ -22,6 +22,7 @@ import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
@ -42,8 +43,10 @@ The state transitioning model does all all the necessary work to work out a vali
3) Create a new state object if the recipient is \0*32
4) Value transfer
== If contract creation ==
4a) Attempt to run transaction data
4b) If valid, use result as code for the new state object
4a) Attempt to run transaction data
4b) If valid, use result as code for the new state object
== end ==
5) Run Script section
6) Derive new state root
@ -74,13 +77,14 @@ type Message interface {
CheckNonce() bool
Data() []byte
BalanceTokenFee() *big.Int
AccessList() types.AccessList
}
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) {
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation, isHomestead bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
if contractCreation && homestead {
if isContractCreation && isHomestead {
gas = params.TxGasContractCreation
} else {
gas = params.TxGas
@ -106,6 +110,10 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error)
}
gas += z * params.TxDataZeroGas
}
if accessList != nil {
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
}
return gas, nil
}
@ -226,7 +234,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
contractCreation := msg.To() == nil
// Pay intrinsic gas
gas, err := IntrinsicGas(st.data, contractCreation, homestead)
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead)
if err != nil {
return nil, 0, false, err, nil
}
@ -234,6 +242,10 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
return nil, 0, false, err, nil
}
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsEIP1559 {
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
}
var (
evm = st.evm
// vm errors do not effect consensus and are therefor

View file

@ -27,6 +27,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/contracts/XDCx/contract"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
)
@ -37,20 +38,21 @@ const (
getDecimalFunction = "decimals"
)
// callmsg implements core.Message to allow passing it as a transaction simulator.
type callmsg struct {
// callMsg implements core.Message to allow passing it as a transaction simulator.
type callMsg struct {
ethereum.CallMsg
}
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) To() *common.Address { return m.CallMsg.To }
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
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 }
func (m callmsg) BalanceTokenFee() *big.Int { return m.CallMsg.BalanceTokenFee }
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) To() *common.Address { return m.CallMsg.To }
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
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 }
func (m callMsg) BalanceTokenFee() *big.Int { return m.CallMsg.BalanceTokenFee }
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
type SimulatedBackend interface {
CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext, statedb *state.StateDB) ([]byte, error)
@ -99,7 +101,7 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,
call.Value = new(big.Int)
}
// Execute the call.
msg := callmsg{call}
msg := callMsg{call}
feeCapacity := state.GetTRC21FeeCapacityFromState(statedb)
if msg.To() != nil {
if value, ok := feeCapacity[*msg.To()]; ok {

View file

@ -24,7 +24,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/log"
)
// nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
@ -99,7 +98,30 @@ func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
// Filter iterates over the list of transactions and removes all of them for which
// the specified function evaluates to true.
// Filter, as opposed to 'filter', re-initialises the heap after the operation is done.
// If you want to do several consecutive filterings, it's therefore better to first
// do a .filter(func1) followed by .Filter(func2) or reheap()
func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
removed := m.filter(filter)
// If transactions were removed, the heap and cache are ruined
if len(removed) > 0 {
m.reheap()
}
return removed
}
func (m *txSortedMap) reheap() {
*m.index = make([]uint64, 0, len(m.items))
for nonce := range m.items {
*m.index = append(*m.index, nonce)
}
heap.Init(m.index)
m.cache = nil
}
// filter is identical to Filter, but **does not** regenerate the heap. This method
// should only be used if followed immediately by a call to Filter or reheap()
func (m *txSortedMap) filter(filter func(*types.Transaction) bool) types.Transactions {
var removed types.Transactions
// Collect all the transactions to filter out
@ -109,14 +131,7 @@ func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transac
delete(m.items, nonce)
}
}
// If transactions were removed, the heap and cache are ruined
if len(removed) > 0 {
*m.index = make([]uint64, 0, len(m.items))
for nonce := range m.items {
*m.index = append(*m.index, nonce)
}
heap.Init(m.index)
m.cache = nil
}
return removed
@ -197,10 +212,7 @@ func (m *txSortedMap) Len() int {
return len(m.items)
}
// Flatten creates a nonce-sorted slice of transactions based on the loosely
// sorted internal representation. The result of the sorting is cached in case
// it's requested again before any modifications are made to the contents.
func (m *txSortedMap) Flatten() types.Transactions {
func (m *txSortedMap) flatten() types.Transactions {
// If the sorting was not cached yet, create and cache it
if m.cache == nil {
m.cache = make(types.Transactions, 0, len(m.items))
@ -209,12 +221,27 @@ func (m *txSortedMap) Flatten() types.Transactions {
}
sort.Sort(types.TxByNonce(m.cache))
}
return m.cache
}
// Flatten creates a nonce-sorted slice of transactions based on the loosely
// sorted internal representation. The result of the sorting is cached in case
// it's requested again before any modifications are made to the contents.
func (m *txSortedMap) Flatten() types.Transactions {
// Copy the cache to prevent accidental modifications
txs := make(types.Transactions, len(m.cache))
copy(txs, m.cache)
cache := m.flatten()
txs := make(types.Transactions, len(cache))
copy(txs, cache)
return txs
}
// LastElement returns the last element of a flattened list, thus, the
// transaction with the highest nonce
func (m *txSortedMap) LastElement() *types.Transaction {
cache := m.flatten()
return cache[len(cache)-1]
}
// txList is a "list" of transactions belonging to an account, sorted by account
// nonce. The same type can be used both for storing contiguous transactions for
// the executable/pending queue; and for storing gapped transactions for the non-
@ -255,11 +282,15 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
return false, nil
}
if old != nil {
threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+int64(priceBump))), big.NewInt(100))
// threshold = oldGP * (100 + priceBump) / 100
a := big.NewInt(100 + int64(priceBump))
a = a.Mul(a, old.GasPrice())
b := big.NewInt(100)
threshold := a.Div(a, b)
// Have to ensure that the new gas price is higher than the old gas
// price as well as checking the percentage threshold to ensure that
// this is accurate for low (Wei-level) gas price replacements
if old.GasPrice().Cmp(tx.GasPrice()) >= 0 || threshold.Cmp(tx.GasPrice()) > 0 {
if old.GasPriceCmp(tx) >= 0 || tx.GasPriceIntCmp(threshold) < 0 {
return false, nil
}
}
@ -303,24 +334,27 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, trc21Issuers map[co
maximum := costLimit
if tx.To() != nil {
if feeCapacity, ok := trc21Issuers[*tx.To()]; ok {
return new(big.Int).Add(costLimit, feeCapacity).Cmp(tx.TxCost(number)) < 0 || tx.Gas() > gasLimit
return tx.Gas() > gasLimit || new(big.Int).Add(costLimit, feeCapacity).Cmp(tx.TxCost(number)) < 0
}
}
return tx.Cost().Cmp(maximum) > 0 || tx.Gas() > gasLimit
return tx.Gas() > gasLimit || tx.Cost().Cmp(maximum) > 0
})
// If the list was strict, filter anything above the lowest nonce
if len(removed) == 0 {
return nil, nil
}
var invalids types.Transactions
if l.strict && len(removed) > 0 {
// If the list was strict, filter anything above the lowest nonce
if l.strict {
lowest := uint64(math.MaxUint64)
for _, tx := range removed {
if nonce := tx.Nonce(); lowest > nonce {
lowest = nonce
}
}
invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
}
l.txs.reheap()
return removed, invalids
}
@ -374,6 +408,12 @@ func (l *txList) Flatten() types.Transactions {
return l.txs.Flatten()
}
// LastElement returns the last element of a flattened list, thus, the
// transaction with the highest nonce
func (l *txList) LastElement() *types.Transaction {
return l.txs.LastElement()
}
// priceHeap is a heap.Interface implementation over transactions for retrieving
// price-sorted transactions to discard when the pool fills up.
type priceHeap []*types.Transaction
@ -383,7 +423,7 @@ func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h priceHeap) Less(i, j int) bool {
// Sort primarily by price, returning the cheaper one
switch h[i].GasPrice().Cmp(h[j].GasPrice()) {
switch h[i].GasPriceCmp(h[j]) {
case -1:
return true
case 1:
@ -406,24 +446,29 @@ func (h *priceHeap) Pop() interface{} {
}
// txPricedList is a price-sorted heap to allow operating on transactions pool
// contents in a price-incrementing way.
// contents in a price-incrementing way. It's built opon the all transactions
// in txpool but only interested in the remote part. It means only remote transactions
// will be considered for tracking, sorting, eviction, etc.
type txPricedList struct {
all *txLookup // Pointer to the map of all transactions
items *priceHeap // Heap of prices of all the stored transactions
stales int // Number of stale price points to (re-heap trigger)
all *txLookup // Pointer to the map of all transactions
remotes *priceHeap // Heap of prices of all the stored **remote** transactions
stales int // Number of stale price points to (re-heap trigger)
}
// newTxPricedList creates a new price-sorted transaction heap.
func newTxPricedList(all *txLookup) *txPricedList {
return &txPricedList{
all: all,
items: new(priceHeap),
all: all,
remotes: new(priceHeap),
}
}
// Put inserts a new transaction into the heap.
func (l *txPricedList) Put(tx *types.Transaction) {
heap.Push(l.items, tx)
func (l *txPricedList) Put(tx *types.Transaction, local bool) {
if local {
return
}
heap.Push(l.remotes, tx)
}
// Removed notifies the prices transaction list that an old transaction dropped
@ -432,100 +477,95 @@ func (l *txPricedList) Put(tx *types.Transaction) {
func (l *txPricedList) Removed(count int) {
// Bump the stale counter, but exit if still too low (< 25%)
l.stales += count
if l.stales <= len(*l.items)/4 {
if l.stales <= len(*l.remotes)/4 {
return
}
// Seems we've reached a critical number of stale transactions, reheap
reheap := make(priceHeap, 0, l.all.Count())
l.stales, l.items = 0, &reheap
l.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
*l.items = append(*l.items, tx)
return true
})
heap.Init(l.items)
l.Reheap()
}
// Cap finds all the transactions below the given price threshold, drops them
// from the priced list and returs them for further removal from the entire pool.
func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions {
// from the priced list and returns them for further removal from the entire pool.
//
// Note: only remote transactions will be considered for eviction.
func (l *txPricedList) Cap(threshold *big.Int) types.Transactions {
drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop
save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
for len(*l.items) > 0 {
for len(*l.remotes) > 0 {
// Discard stale transactions if found during cleanup
tx := heap.Pop(l.items).(*types.Transaction)
if l.all.Get(tx.Hash()) == nil {
cheapest := (*l.remotes)[0]
if l.all.GetRemote(cheapest.Hash()) == nil { // Removed or migrated
heap.Pop(l.remotes)
l.stales--
continue
}
// Stop the discards if we've reached the threshold
if tx.GasPrice().Cmp(threshold) >= 0 {
save = append(save, tx)
if cheapest.GasPriceIntCmp(threshold) >= 0 {
break
}
// Non stale transaction found, discard unless local
if local.containsTx(tx) {
save = append(save, tx)
} else {
drop = append(drop, tx)
}
}
for _, tx := range save {
heap.Push(l.items, tx)
heap.Pop(l.remotes)
drop = append(drop, cheapest)
}
return drop
}
// Underpriced checks whether a transaction is cheaper than (or as cheap as) the
// lowest priced transaction currently being tracked.
func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) bool {
// Local transactions cannot be underpriced
if local.containsTx(tx) {
return false
}
// lowest priced (remote) transaction currently being tracked.
func (l *txPricedList) Underpriced(tx *types.Transaction) bool {
// Discard stale price points if found at the heap start
for len(*l.items) > 0 {
head := []*types.Transaction(*l.items)[0]
if l.all.Get(head.Hash()) == nil {
for len(*l.remotes) > 0 {
head := []*types.Transaction(*l.remotes)[0]
if l.all.GetRemote(head.Hash()) == nil { // Removed or migrated
l.stales--
heap.Pop(l.items)
heap.Pop(l.remotes)
continue
}
break
}
// Check if the transaction is underpriced or not
if len(*l.items) == 0 {
log.Error("Pricing query for empty pool") // This cannot happen, print to catch programming errors
return false
if len(*l.remotes) == 0 {
return false // There is no remote transaction at all.
}
cheapest := []*types.Transaction(*l.items)[0]
return cheapest.GasPrice().Cmp(tx.GasPrice()) >= 0
// If the remote transaction is even cheaper than the
// cheapest one tracked locally, reject it.
cheapest := []*types.Transaction(*l.remotes)[0]
return cheapest.GasPriceCmp(tx) >= 0
}
// Discard finds a number of most underpriced transactions, removes them from the
// priced list and returns them for further removal from the entire pool.
func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions {
drop := make(types.Transactions, 0, count) // Remote underpriced transactions to drop
save := make(types.Transactions, 0, 64) // Local underpriced transactions to keep
for len(*l.items) > 0 && count > 0 {
//
// Note local transaction won't be considered for eviction.
func (l *txPricedList) Discard(slots int, force bool) (types.Transactions, bool) {
drop := make(types.Transactions, 0, slots) // Remote underpriced transactions to drop
for len(*l.remotes) > 0 && slots > 0 {
// Discard stale transactions if found during cleanup
tx := heap.Pop(l.items).(*types.Transaction)
if l.all.Get(tx.Hash()) == nil {
tx := heap.Pop(l.remotes).(*types.Transaction)
if l.all.GetRemote(tx.Hash()) == nil { // Removed or migrated
l.stales--
continue
}
// Non stale transaction found, discard unless local
if local.containsTx(tx) {
save = append(save, tx)
} else {
drop = append(drop, tx)
count--
// Non stale transaction found, discard it
drop = append(drop, tx)
slots -= numSlots(tx)
}
// If we still can't make enough room for the new transaction
if slots > 0 && !force {
for _, tx := range drop {
heap.Push(l.remotes, tx)
}
return nil, false
}
for _, tx := range save {
heap.Push(l.items, tx)
}
return drop
return drop, true
}
// Reheap forcibly rebuilds the heap based on the current remote transaction set.
func (l *txPricedList) Reheap() {
reheap := make(priceHeap, 0, l.all.RemoteCount())
l.stales, l.remotes = 0, &reheap
l.all.Range(func(hash common.Hash, tx *types.Transaction, local bool) bool {
*l.remotes = append(*l.remotes, tx)
return true
}, false, true) // Only iterate remotes
heap.Init(l.remotes)
}

View file

@ -17,6 +17,7 @@
package core
import (
"math/big"
"math/rand"
"testing"
@ -49,3 +50,21 @@ func TestStrictTxListAdd(t *testing.T) {
}
}
}
func BenchmarkTxListAdd(t *testing.B) {
// Generate a list of transactions to insert
key, _ := crypto.GenerateKey()
txs := make(types.Transactions, 100000)
for i := 0; i < len(txs); i++ {
txs[i] = transaction(uint64(i), 0, key)
}
// Insert the transactions in a random order
list := newTxList(true)
priceLimit := big.NewInt(int64(DefaultTxPoolConfig.PriceLimit))
t.ResetTimer()
for _, v := range rand.Perm(len(txs)) {
list.Add(txs[v], DefaultTxPoolConfig.PriceBump)
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump, nil, nil)
}
}

View file

@ -39,9 +39,25 @@ import (
const (
// chainHeadChanSize is the size of channel listening to ChainHeadEvent.
chainHeadChanSize = 10
// txSlotSize is used to calculate how many data slots a single transaction
// takes up based on its size. The slots are used as DoS protection, ensuring
// that validating a new transaction remains a constant operation (in reality
// O(maxslots), where max slots are 4 currently).
txSlotSize = 32 * 1024
// txMaxSize is the maximum size a single transaction can have. This field has
// non-trivial consequences: larger transactions are significantly harder and
// more expensive to propagate; larger transactions also take more resources
// to validate whether they fit into the pool or not.
txMaxSize = 2 * txSlotSize // 64KB, don't bump without EIP-2464 support
)
var (
// ErrAlreadyKnown is returned if the transactions is already contained
// within the pool.
ErrAlreadyKnown = errors.New("already known")
// ErrInvalidSender is returned if the transaction contains an invalid signature.
ErrInvalidSender = errors.New("invalid sender")
@ -53,6 +69,10 @@ var (
// configured for the transaction pool.
ErrUnderpriced = errors.New("transaction underpriced")
// ErrTxPoolOverflow is returned if the transaction pool is full and can't accpet
// another remote transaction.
ErrTxPoolOverflow = errors.New("txpool is full")
// ErrReplaceUnderpriced is returned if a transaction is attempted to be replaced
// with a different one without the required price bump.
ErrReplaceUnderpriced = errors.New("replacement transaction underpriced")
@ -69,7 +89,7 @@ var (
// maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit")
// ErrNegativeValue is a sanity error to ensure noone is able to specify a
// ErrNegativeValue is a sanity error to ensure no one is able to specify a
// transaction with a negative value.
ErrNegativeValue = errors.New("negative value")
@ -104,15 +124,19 @@ var (
queuedReplaceMeter = metrics.NewRegisteredMeter("txpool/queued/replace", nil)
queuedRateLimitMeter = metrics.NewRegisteredMeter("txpool/queued/ratelimit", nil) // Dropped due to rate limiting
queuedNofundsMeter = metrics.NewRegisteredMeter("txpool/queued/nofunds", nil) // Dropped due to out-of-funds
queuedEvictionMeter = metrics.NewRegisteredMeter("txpool/queued/eviction", nil) // Dropped due to lifetime
// General tx metrics
validMeter = metrics.NewRegisteredMeter("txpool/valid", nil)
knownTxMeter = metrics.NewRegisteredMeter("txpool/known", nil)
validTxMeter = metrics.NewRegisteredMeter("txpool/valid", nil)
invalidTxMeter = metrics.NewRegisteredMeter("txpool/invalid", nil)
underpricedTxMeter = metrics.NewRegisteredMeter("txpool/underpriced", nil)
overflowedTxMeter = metrics.NewRegisteredMeter("txpool/overflowed", nil)
pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil)
queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil)
localGauge = metrics.NewRegisteredGauge("txpool/local", nil)
slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil)
)
// TxStatus is the current status of a transaction as seen by the pool.
@ -259,6 +283,7 @@ type TxPool struct {
reorgShutdownCh chan struct{} // requests shutdown of scheduleReorgLoop
wg sync.WaitGroup // tracks loop, scheduleReorgLoop
eip2718 bool // Fork indicator whether we are using EIP-2718 type transactions.
IsSigner func(address common.Address) bool
trc21FeeCapacity map[common.Address]*big.Int
}
@ -278,7 +303,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
config: config,
chainconfig: chainconfig,
chain: chain,
signer: types.NewEIP155Signer(chainconfig.ChainId),
signer: types.LatestSigner(chainconfig),
pending: make(map[common.Address]*txList),
queue: make(map[common.Address]*txList),
beats: make(map[common.Address]time.Time),
@ -369,7 +394,7 @@ func (pool *TxPool) loop() {
prevPending, prevQueued, prevStales = pending, queued, stales
}
// Handle inactive account transaction eviction
// Handle inactive account transaction eviction
case <-evict.C:
pool.mu.Lock()
for addr := range pool.queue {
@ -379,14 +404,16 @@ func (pool *TxPool) loop() {
}
// Any non-locals old enough should be removed
if time.Since(pool.beats[addr]) > pool.config.Lifetime {
for _, tx := range pool.queue[addr].Flatten() {
list := pool.queue[addr].Flatten()
for _, tx := range list {
pool.removeTx(tx.Hash(), true)
}
queuedEvictionMeter.Mark(int64(len(list)))
}
}
pool.mu.Unlock()
// Handle local transaction journal rotation
// Handle local transaction journal rotation
case <-journal.C:
if pool.journal != nil {
pool.mu.Lock()
@ -435,7 +462,7 @@ func (pool *TxPool) SetGasPrice(price *big.Int) {
defer pool.mu.Unlock()
pool.gasPrice = price
for _, tx := range pool.priced.Cap(price, pool.locals) {
for _, tx := range pool.priced.Cap(price) {
pool.removeTx(tx.Hash(), false)
}
log.Info("Transaction pool price threshold updated", "price", price)
@ -539,6 +566,14 @@ func (pool *TxPool) GetSender(tx *types.Transaction) (common.Address, error) {
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Accept only legacy transactions until EIP-2718/2930 activates.
if !pool.eip2718 && tx.Type() != types.LegacyTxType {
return ErrTxTypeNotSupported
}
// Reject transactions over defined size to prevent DOS attacks
if uint64(tx.Size()) > txMaxSize {
return ErrOversizedData
}
// check if sender is in black list
if tx.From() != nil && common.Blacklist[*tx.From()] {
return fmt.Errorf("Reject transaction with sender in black-list: %v", tx.From().Hex())
@ -547,11 +582,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if tx.To() != nil && common.Blacklist[*tx.To()] {
return fmt.Errorf("Reject transaction with receiver in black-list: %v", tx.To().Hex())
}
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
return ErrOversizedData
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 {
@ -561,14 +591,13 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit
}
// Make sure the transaction is signed properly
// Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx)
if err != nil {
return ErrInvalidSender
}
// Drop non-local transactions under our own minimal accepted gas price
local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
if !local && tx.GasPriceIntCmp(pool.gasPrice) < 0 {
if !tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from)) {
return ErrUnderpriced
}
@ -606,7 +635,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if tx.To() == nil || (tx.To() != nil && !tx.IsSpecialTransaction()) {
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true)
intrGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true)
if err != nil {
return err
}
@ -659,39 +688,50 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
hash := tx.Hash()
if pool.all.Get(hash) != nil {
log.Trace("Discarding already known transaction", "hash", hash)
return false, fmt.Errorf("known transaction: %x", hash)
knownTxMeter.Mark(1)
return false, ErrAlreadyKnown
}
// Make the local flag. If it's from local source or it's from the network but
// the sender is marked as local previously, treat it as the local transaction.
isLocal := local || pool.locals.containsTx(tx)
// If the transaction fails basic validation, discard it
if err := pool.validateTx(tx, local); err != nil {
if err := pool.validateTx(tx, isLocal); err != nil {
log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
invalidTxMeter.Mark(1)
return false, err
}
from, _ := types.Sender(pool.signer, tx) // already validated
if tx.IsSpecialTransaction() && pool.IsSigner != nil && pool.IsSigner(from) && pool.pendingNonces.get(from) == tx.Nonce() {
return pool.promoteSpecialTx(from, tx)
return pool.promoteSpecialTx(from, tx, isLocal)
}
// If the transaction pool is full, discard underpriced transactions
if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
log.Debug("Add transaction to pool full", "hash", hash, "nonce", tx.Nonce())
// If the new transaction is underpriced, don't accept it
if !local && pool.priced.Underpriced(tx, pool.locals) {
if !isLocal && pool.priced.Underpriced(tx) {
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
underpricedTxMeter.Mark(1)
return false, ErrUnderpriced
}
// New transaction is better than our worse ones, make room for it
drop := pool.priced.Discard(pool.all.Count()-int(pool.config.GlobalSlots+pool.config.GlobalQueue-1), pool.locals)
// New transaction is better than our worse ones, make room for it.
// If it's a local transaction, forcibly discard all available transactions.
// Otherwise if we can't make enough room for new one, abort the operation.
drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal)
// Special case, we still can't make the room for the new remote one.
if !isLocal && !success {
log.Trace("Discarding overflown transaction", "hash", hash)
overflowedTxMeter.Mark(1)
return false, ErrTxPoolOverflow
}
// Kick out the underpriced remote transactions.
for _, tx := range drop {
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "price", tx.GasPrice())
underpricedTxMeter.Mark(1)
pool.removeTx(tx.Hash(), false)
}
}
// Try to replace an existing transaction in the pending pool
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
// Nonce already pending, check if required price bump is met
@ -706,28 +746,28 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
pool.priced.Removed(1)
pendingReplaceMeter.Mark(1)
}
pool.all.Add(tx)
pool.priced.Put(tx)
pool.all.Add(tx, isLocal)
pool.priced.Put(tx, isLocal)
pool.journalTx(from, tx)
pool.queueTxEvent(tx)
log.Trace("Pooled new executable transaction", "hash", hash, "from", from, "to", tx.To())
// Successful promotion, bump the heartbeat
pool.beats[from] = time.Now()
return old != nil, nil
}
// New transaction isn't replacing a pending one, push into queue
replaced, err = pool.enqueueTx(hash, tx)
replaced, err = pool.enqueueTx(hash, tx, isLocal, true)
if err != nil {
return false, err
}
// Mark local addresses and journal local transactions
if local {
if !pool.locals.contains(from) {
log.Info("Setting new local account", "address", from)
pool.locals.add(from)
}
if local && !pool.locals.contains(from) {
log.Info("Setting new local account", "address", from)
pool.locals.add(from)
pool.priced.Removed(pool.all.RemoteToLocals(pool.locals)) // Migrate the remotes if it's marked as local first time.
}
if local || pool.locals.contains(from) {
if isLocal {
localGauge.Inc(1)
}
pool.journalTx(from, tx)
@ -739,7 +779,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
// enqueueTx inserts a new transaction into the non-executable transaction queue.
//
// Note, this method assumes the pool lock is held!
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, error) {
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction, local bool, addAll bool) (bool, error) {
// Try to insert the transaction into the future queue
from, _ := types.Sender(pool.signer, tx) // already validated
if pool.queue[from] == nil {
@ -760,9 +800,18 @@ func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) (bool, er
// Nothing was replaced, bump the queued counter
queuedGauge.Inc(1)
}
if pool.all.Get(hash) == nil {
pool.all.Add(tx)
pool.priced.Put(tx)
// If the transaction isn't in lookup set but it's expected to be there,
// show the error log.
if pool.all.Get(hash) == nil && !addAll {
log.Error("Missing transaction in lookup set, please report the issue", "hash", hash)
}
if addAll {
pool.all.Add(tx, local)
pool.priced.Put(tx, local)
}
// If we never record the heartbeat, do it right now.
if _, exist := pool.beats[from]; !exist {
pool.beats[from] = time.Now()
}
return old != nil, nil
}
@ -803,30 +852,26 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
if old != nil {
pool.all.Remove(old.Hash())
pool.priced.Removed(1)
pendingReplaceMeter.Mark(1)
} else {
// Nothing was replaced, bump the pending counter
pendingGauge.Inc(1)
}
// Failsafe to work around direct pending inserts (tests)
if pool.all.Get(hash) == nil {
pool.all.Add(tx)
pool.priced.Put(tx)
}
// Set the potentially new pending nonce and notify any subsystems of the new tx
pool.beats[addr] = time.Now()
pool.pendingNonces.set(addr, tx.Nonce()+1)
// Successful promotion, bump the heartbeat
pool.beats[addr] = time.Now()
return true
}
func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction) (bool, error) {
func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction, isLocal bool) (bool, error) {
// Try to insert the transaction into the pending queue
if pool.pending[addr] == nil {
pool.pending[addr] = newTxList(true)
}
list := pool.pending[addr]
old := list.txs.Get(tx.Nonce())
if old != nil && old.IsSpecialTransaction() {
return false, ErrDuplicateSpecialTransaction
@ -849,7 +894,7 @@ func (pool *TxPool) promoteSpecialTx(addr common.Address, tx *types.Transaction)
}
// Failsafe to work around direct pending inserts (tests)
if pool.all.Get(tx.Hash()) == nil {
pool.all.Add(tx)
pool.all.Add(tx, isLocal)
}
// Set the potentially new pending nonce and notify any subsystems of the new tx
pool.beats[addr] = time.Now()
@ -889,7 +934,7 @@ func (pool *TxPool) AddRemotesSync(txs []*types.Transaction) []error {
}
// This is like AddRemotes with a single transaction, but waits for pool reorganization. Tests use this method.
func (pool *TxPool) AddRemoteSync(tx *types.Transaction) error {
func (pool *TxPool) addRemoteSync(tx *types.Transaction) error {
errs := pool.AddRemotesSync([]*types.Transaction{tx})
return errs[0]
}
@ -905,15 +950,48 @@ func (pool *TxPool) AddRemote(tx *types.Transaction) error {
// addTxs attempts to queue a batch of transactions if they are valid.
func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
// Cache senders in transactions before obtaining lock (pool.signer is immutable)
for _, tx := range txs {
types.Sender(pool.signer, tx)
// Filter out known ones without obtaining the pool lock or recovering signatures
var (
errs = make([]error, len(txs))
news = make([]*types.Transaction, 0, len(txs))
)
for i, tx := range txs {
// If the transaction is known, pre-set the error slot
if pool.all.Get(tx.Hash()) != nil {
errs[i] = ErrAlreadyKnown
knownTxMeter.Mark(1)
continue
}
// Exclude transactions with invalid signatures as soon as
// possible and cache senders in transactions before
// obtaining lock
_, err := types.Sender(pool.signer, tx)
if err != nil {
errs[i] = ErrInvalidSender
invalidTxMeter.Mark(1)
continue
}
// Accumulate all unknown transactions for deeper processing
news = append(news, tx)
}
if len(news) == 0 {
return errs
}
// Process all the new transaction and merge any errors into the original slice
pool.mu.Lock()
errs, dirtyAddrs := pool.addTxsLocked(txs, local)
newErrs, dirtyAddrs := pool.addTxsLocked(news, local)
pool.mu.Unlock()
var nilSlot = 0
for _, err := range newErrs {
for errs[nilSlot] != nil {
nilSlot++
}
errs[nilSlot] = err
nilSlot++
}
// Reorg the pool internals if needed and return
done := pool.requestPromoteExecutables(dirtyAddrs)
if sync {
<-done
@ -933,26 +1011,29 @@ func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) ([]error,
dirty.addTx(tx)
}
}
validMeter.Mark(int64(len(dirty.accounts)))
validTxMeter.Mark(int64(len(dirty.accounts)))
return errs, dirty
}
// Status returns the status (unknown/pending/queued) of a batch of transactions
// identified by their hashes.
func (pool *TxPool) Status(hashes []common.Hash) []TxStatus {
pool.mu.RLock()
defer pool.mu.RUnlock()
status := make([]TxStatus, len(hashes))
for i, hash := range hashes {
if tx := pool.all.Get(hash); tx != nil {
from, _ := types.Sender(pool.signer, tx) // already validated
if pool.pending[from] != nil && pool.pending[from].txs.items[tx.Nonce()] != nil {
status[i] = TxStatusPending
} else {
status[i] = TxStatusQueued
}
tx := pool.Get(hash)
if tx == nil {
continue
}
from, _ := types.Sender(pool.signer, tx) // already validated
pool.mu.RLock()
if txList := pool.pending[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil {
status[i] = TxStatusPending
} else if txList := pool.queue[from]; txList != nil && txList.txs.items[tx.Nonce()] != nil {
status[i] = TxStatusQueued
}
// implicit else: the tx may have been included into a block between
// checking pool.Get and obtaining the lock. In that case, TxStatusUnknown is correct
pool.mu.RUnlock()
}
return status
}
@ -962,6 +1043,12 @@ func (pool *TxPool) Get(hash common.Hash) *types.Transaction {
return pool.all.Get(hash)
}
// Has returns an indicator whether txpool has a transaction cached with the
// given hash.
func (pool *TxPool) Has(hash common.Hash) bool {
return pool.all.Get(hash) != nil
}
// removeTx removes a single transaction from the queue, moving all subsequent
// transactions back to the future queue.
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
@ -986,11 +1073,11 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
// If no more pending transactions are left, remove the list
if pending.Empty() {
delete(pool.pending, addr)
delete(pool.beats, addr)
}
// Postpone any invalidated transactions
for _, tx := range invalids {
pool.enqueueTx(tx.Hash(), tx)
// Internal shuffle shouldn't touch the lookup set.
pool.enqueueTx(tx.Hash(), tx, false, false)
}
// Update the account nonce if needed
pool.pendingNonces.setIfLower(addr, tx.Nonce())
@ -1007,11 +1094,12 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
}
if future.Empty() {
delete(pool.queue, addr)
delete(pool.beats, addr)
}
}
}
// requestPromoteExecutables requests a pool reset to the new head block.
// requestReset requests a pool reset to the new head block.
// The returned channel is closed when the reset has occurred.
func (pool *TxPool) requestReset(oldHead *types.Header, newHead *types.Header) chan struct{} {
select {
@ -1118,7 +1206,10 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
defer close(done)
var promoteAddrs []common.Address
if dirtyAccounts != nil {
if dirtyAccounts != nil && reset == nil {
// Only dirty accounts need to be promoted, unless we're resetting.
// For resets, all addresses in the tx queue will be promoted and
// the flatten operation can be avoided.
promoteAddrs = dirtyAccounts.flatten()
}
pool.mu.Lock()
@ -1134,20 +1225,14 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
}
}
// Reset needs promote for all addresses
promoteAddrs = promoteAddrs[:0]
promoteAddrs = make([]common.Address, 0, len(pool.queue))
for addr := range pool.queue {
promoteAddrs = append(promoteAddrs, addr)
}
}
// Check for pending transactions for every account that sent new ones
promoted := pool.promoteExecutables(promoteAddrs)
for _, tx := range promoted {
addr, _ := types.Sender(pool.signer, tx)
if _, ok := events[addr]; !ok {
events[addr] = newTxSortedMap()
}
events[addr].Put(tx)
}
// If a new block appeared, validate the pool of pending transactions. This will
// remove any transaction that has been included in the block or was invalidated
// because of another transaction (e.g. higher gas price).
@ -1160,12 +1245,19 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt
// Update all accounts to the latest known pending nonce
for addr, list := range pool.pending {
txs := list.Flatten() // Heavy but will be cached and is needed by the miner anyway
pool.pendingNonces.set(addr, txs[len(txs)-1].Nonce()+1)
highestPending := list.LastElement()
pool.pendingNonces.set(addr, highestPending.Nonce()+1)
}
pool.mu.Unlock()
// Notify subsystems for newly added transactions
for _, tx := range promoted {
addr, _ := types.Sender(pool.signer, tx)
if _, ok := events[addr]; !ok {
events[addr] = newTxSortedMap()
}
events[addr].Put(tx)
}
if len(events) > 0 {
var txs []*types.Transaction
for _, set := range events {
@ -1200,44 +1292,45 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
// head from the chain.
// If that is the case, we don't have the lost transactions any more, and
// there's nothing to add
if newNum < oldNum {
// If the reorg ended up on a lower number, it's indicative of setHead being the cause
log.Debug("Skipping transaction reset caused by setHead",
"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum)
} else {
if newNum >= oldNum {
// If we reorged to a same or higher number, then it's not a case of setHead
log.Warn("Transaction pool reset with missing oldhead",
"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum)
}
return
}
for rem.NumberU64() > add.NumberU64() {
discarded = append(discarded, rem.Transactions()...)
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
return
}
}
for add.NumberU64() > rem.NumberU64() {
included = append(included, add.Transactions()...)
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
return
// If the reorg ended up on a lower number, it's indicative of setHead being the cause
log.Debug("Skipping transaction reset caused by setHead",
"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum)
// We still need to update the current state s.th. the lost transactions can be readded by the user
} else {
for rem.NumberU64() > add.NumberU64() {
discarded = append(discarded, rem.Transactions()...)
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
return
}
}
}
for rem.Hash() != add.Hash() {
discarded = append(discarded, rem.Transactions()...)
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
return
for add.NumberU64() > rem.NumberU64() {
included = append(included, add.Transactions()...)
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
return
}
}
included = append(included, add.Transactions()...)
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
return
for rem.Hash() != add.Hash() {
discarded = append(discarded, rem.Transactions()...)
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
return
}
included = append(included, add.Transactions()...)
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
return
}
}
reinject = types.TxDifference(discarded, included)
}
reinject = types.TxDifference(discarded, included)
}
}
// Initialize the internal state to the current head
@ -1258,6 +1351,10 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
log.Debug("Reinjecting stale transactions", "count", len(reinject))
senderCacher.recover(pool.signer, reinject)
pool.addTxsLocked(reinject, false)
// Update all fork indicator by next pending block number.
next := new(big.Int).Add(newHead.Number, big.NewInt(1))
pool.eip2718 = pool.chainconfig.IsEIP1559(next)
}
// promoteExecutables moves transactions that have become processable from the
@ -1283,8 +1380,8 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
for _, tx := range forwards {
hash := tx.Hash()
pool.all.Remove(hash)
log.Trace("Removed old queued transaction", "hash", hash)
}
log.Trace("Removed old queued transactions", "count", len(forwards))
// Drop all transactions that are too costly (low balance or out of gas)
var number *big.Int = nil
if pool.chain.CurrentHeader() != nil {
@ -1294,8 +1391,8 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
for _, tx := range drops {
hash := tx.Hash()
pool.all.Remove(hash)
log.Trace("Removed unpayable queued transaction", "hash", hash)
}
log.Trace("Removed unpayable queued transactions", "count", len(drops))
queuedNofundsMeter.Mark(int64(len(drops)))
// Gather all executable transactions and promote them
@ -1303,10 +1400,10 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
for _, tx := range readies {
hash := tx.Hash()
if pool.promoteTx(addr, hash, tx) {
log.Trace("Promoting queued transaction", "hash", hash)
promoted = append(promoted, tx)
}
}
log.Trace("Promoted queued transactions", "count", len(promoted))
queuedGauge.Dec(int64(len(readies)))
// Drop all transactions over the allowed limit
@ -1329,6 +1426,7 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
// Delete the entire queue entry if it became empty.
if list.Empty() {
delete(pool.queue, addr)
delete(pool.beats, addr)
}
}
return promoted
@ -1498,7 +1596,9 @@ func (pool *TxPool) demoteUnexecutables() {
for _, tx := range invalids {
hash := tx.Hash()
log.Trace("Demoting pending transaction", "hash", hash)
pool.enqueueTx(hash, tx)
// Internal shuffle shouldn't touch the lookup set.
pool.enqueueTx(hash, tx, false, false)
}
pendingGauge.Dec(int64(len(olds) + len(drops) + len(invalids)))
if pool.locals.contains(addr) {
@ -1510,14 +1610,17 @@ func (pool *TxPool) demoteUnexecutables() {
for _, tx := range gapped {
hash := tx.Hash()
log.Warn("Demoting invalidated transaction", "hash", hash)
pool.enqueueTx(hash, tx)
// Internal shuffle shouldn't touch the lookup set.
pool.enqueueTx(hash, tx, false, false)
}
pendingGauge.Dec(int64(len(gapped)))
// This might happen in a reorg, so log it to the metering
blockReorgInvalidatedTx.Mark(int64(len(gapped)))
}
// Delete the entire queue entry if it became empty.
// Delete the entire pending entry if it became empty.
if list.Empty() {
delete(pool.pending, addr)
delete(pool.beats, addr)
}
}
}
@ -1561,6 +1664,10 @@ func (as *accountSet) contains(addr common.Address) bool {
return exist
}
func (as *accountSet) empty() bool {
return len(as.accounts) == 0
}
// containsTx checks if the sender of a given tx is within the set. If the sender
// cannot be derived, this method returns false.
func (as *accountSet) containsTx(tx *types.Transaction) bool {
@ -1604,8 +1711,8 @@ func (as *accountSet) merge(other *accountSet) {
as.cache = nil
}
// txLookup is used internally by TxPool to track transactions while allowing lookup without
// mutex contention.
// txLookup is used internally by TxPool to track transactions while allowing
// lookup without mutex contention.
//
// Note, although this type is properly protected against concurrent access, it
// is **not** a type that should ever be mutated or even exposed outside of the
@ -1613,26 +1720,43 @@ func (as *accountSet) merge(other *accountSet) {
// internal mechanisms. The sole purpose of the type is to permit out-of-bound
// peeking into the pool in TxPool.Get without having to acquire the widely scoped
// TxPool.mu mutex.
//
// This lookup set combines the notion of "local transactions", which is useful
// to build upper-level structure.
type txLookup struct {
all map[common.Hash]*types.Transaction
lock sync.RWMutex
slots int
lock sync.RWMutex
locals map[common.Hash]*types.Transaction
remotes map[common.Hash]*types.Transaction
}
// newTxLookup returns a new txLookup structure.
func newTxLookup() *txLookup {
return &txLookup{
all: make(map[common.Hash]*types.Transaction),
locals: make(map[common.Hash]*types.Transaction),
remotes: make(map[common.Hash]*types.Transaction),
}
}
// Range calls f on each key and value present in the map.
func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction) bool) {
// Range calls f on each key and value present in the map. The callback passed
// should return the indicator whether the iteration needs to be continued.
// Callers need to specify which set (or both) to be iterated.
func (t *txLookup) Range(f func(hash common.Hash, tx *types.Transaction, local bool) bool, local bool, remote bool) {
t.lock.RLock()
defer t.lock.RUnlock()
for key, value := range t.all {
if !f(key, value) {
break
if local {
for key, value := range t.locals {
if !f(key, value, true) {
return
}
}
}
if remote {
for key, value := range t.remotes {
if !f(key, value, false) {
return
}
}
}
}
@ -1642,23 +1766,73 @@ func (t *txLookup) Get(hash common.Hash) *types.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.all[hash]
if tx := t.locals[hash]; tx != nil {
return tx
}
return t.remotes[hash]
}
// Count returns the current number of items in the lookup.
// GetLocal returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) GetLocal(hash common.Hash) *types.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.locals[hash]
}
// GetRemote returns a transaction if it exists in the lookup, or nil if not found.
func (t *txLookup) GetRemote(hash common.Hash) *types.Transaction {
t.lock.RLock()
defer t.lock.RUnlock()
return t.remotes[hash]
}
// Count returns the current number of transactions in the lookup.
func (t *txLookup) Count() int {
t.lock.RLock()
defer t.lock.RUnlock()
return len(t.all)
return len(t.locals) + len(t.remotes)
}
// LocalCount returns the current number of local transactions in the lookup.
func (t *txLookup) LocalCount() int {
t.lock.RLock()
defer t.lock.RUnlock()
return len(t.locals)
}
// RemoteCount returns the current number of remote transactions in the lookup.
func (t *txLookup) RemoteCount() int {
t.lock.RLock()
defer t.lock.RUnlock()
return len(t.remotes)
}
// Slots returns the current number of slots used in the lookup.
func (t *txLookup) Slots() int {
t.lock.RLock()
defer t.lock.RUnlock()
return t.slots
}
// Add adds a transaction to the lookup.
func (t *txLookup) Add(tx *types.Transaction) {
func (t *txLookup) Add(tx *types.Transaction, local bool) {
t.lock.Lock()
defer t.lock.Unlock()
t.all[tx.Hash()] = tx
t.slots += numSlots(tx)
slotsGauge.Update(int64(t.slots))
if local {
t.locals[tx.Hash()] = tx
} else {
t.remotes[tx.Hash()] = tx
}
}
// Remove removes a transaction from the lookup.
@ -1666,5 +1840,39 @@ func (t *txLookup) Remove(hash common.Hash) {
t.lock.Lock()
defer t.lock.Unlock()
delete(t.all, hash)
tx, ok := t.locals[hash]
if !ok {
tx, ok = t.remotes[hash]
}
if !ok {
log.Error("No transaction found to be deleted", "hash", hash)
return
}
t.slots -= numSlots(tx)
slotsGauge.Update(int64(t.slots))
delete(t.locals, hash)
delete(t.remotes, hash)
}
// RemoteToLocals migrates the transactions belongs to the given locals to locals
// set. The assumption is held the locals set is thread-safe to be used.
func (t *txLookup) RemoteToLocals(locals *accountSet) int {
t.lock.Lock()
defer t.lock.Unlock()
var migrated int
for hash, tx := range t.remotes {
if locals.containsTx(tx) {
t.locals[hash] = tx
delete(t.remotes, hash)
migrated += 1
}
}
return migrated
}
// numSlots calculates the number of slots needed for a single transaction.
func numSlots(tx *types.Transaction) int {
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
}

View file

@ -94,10 +94,18 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec
return tx
}
func pricedDataTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey, bytes uint64) *types.Transaction {
data := make([]byte, bytes)
rand.Read(data)
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(0), gaslimit, gasprice, data), types.HomesteadSigner{}, key)
return tx
}
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
diskdb := rawdb.NewMemoryDatabase()
statedb, _ := state.New(common.Hash{}, state.NewDatabase(diskdb))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
blockchain := &testBlockChain{statedb, 10000000, new(event.Feed)}
key, _ := crypto.GenerateKey()
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@ -115,8 +123,10 @@ func validateTxPoolInternals(pool *TxPool) error {
if total := pool.all.Count(); total != pending+queued {
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
}
if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued {
return fmt.Errorf("total priced transaction count %d != %d pending + %d queued", priced, pending, queued)
pool.priced.Reheap()
priced, remote := pool.priced.remotes.Len(), pool.all.RemoteCount()
if priced != remote {
return fmt.Errorf("total priced transaction count %d != %d", priced, remote)
}
// Ensure the next nonce to assign is the correct one
for addr, txs := range pool.pending {
@ -289,7 +299,7 @@ func TestTransactionQueue(t *testing.T) {
pool.currentState.AddBalance(from, big.NewInt(1000))
<-pool.requestReset(nil, nil)
pool.enqueueTx(tx.Hash(), tx)
pool.enqueueTx(tx.Hash(), tx, false, true)
<-pool.requestPromoteExecutables(newAccountSet(pool.signer, from))
if len(pool.pending) != 1 {
t.Error("expected valid txs to be 1 is", len(pool.pending))
@ -298,7 +308,7 @@ func TestTransactionQueue(t *testing.T) {
tx = transaction(1, 100, key)
from, _ = deriveSender(tx)
pool.currentState.SetNonce(from, 2)
pool.enqueueTx(tx.Hash(), tx)
pool.enqueueTx(tx.Hash(), tx, false, true)
<-pool.requestPromoteExecutables(newAccountSet(pool.signer, from))
if _, ok := pool.pending[from].txs.items[tx.Nonce()]; ok {
@ -323,9 +333,9 @@ func TestTransactionQueue2(t *testing.T) {
pool.currentState.AddBalance(from, big.NewInt(1000))
pool.reset(nil, nil)
pool.enqueueTx(tx1.Hash(), tx1)
pool.enqueueTx(tx2.Hash(), tx2)
pool.enqueueTx(tx3.Hash(), tx3)
pool.enqueueTx(tx1.Hash(), tx1, false, true)
pool.enqueueTx(tx2.Hash(), tx2, false, true)
pool.enqueueTx(tx3.Hash(), tx3, false, true)
pool.promoteExecutables([]common.Address{from})
if len(pool.pending) != 1 {
@ -488,7 +498,7 @@ func TestTransactionDropping(t *testing.T) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000))
// Add some pending and some queued transactions
@ -500,12 +510,21 @@ func TestTransactionDropping(t *testing.T) {
tx11 = transaction(11, 200, key)
tx12 = transaction(12, 300, key)
)
pool.all.Add(tx0, false)
pool.priced.Put(tx0, false)
pool.promoteTx(account, tx0.Hash(), tx0)
pool.all.Add(tx1, false)
pool.priced.Put(tx1, false)
pool.promoteTx(account, tx1.Hash(), tx1)
pool.all.Add(tx2, false)
pool.priced.Put(tx2, false)
pool.promoteTx(account, tx2.Hash(), tx2)
pool.enqueueTx(tx10.Hash(), tx10)
pool.enqueueTx(tx11.Hash(), tx11)
pool.enqueueTx(tx12.Hash(), tx12)
pool.enqueueTx(tx10.Hash(), tx10, false, true)
pool.enqueueTx(tx11.Hash(), tx11, false, true)
pool.enqueueTx(tx12.Hash(), tx12, false, true)
// Check that pre and post validations leave the pool as is
if pool.pending[account].Len() != 3 {
@ -698,7 +717,7 @@ func TestTransactionGapFilling(t *testing.T) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
// Keep track of transaction events to ensure all executables get announced
@ -725,7 +744,7 @@ func TestTransactionGapFilling(t *testing.T) {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Fill the nonce gap and ensure all transactions become pending
if err := pool.AddRemoteSync(transaction(1, 100000, key)); err != nil {
if err := pool.addRemoteSync(transaction(1, 100000, key)); err != nil {
t.Fatalf("failed to add gapped transaction: %v", err)
}
pending, queued = pool.Stats()
@ -752,12 +771,12 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
testTxPoolConfig.AccountQueue = 10
// Keep queuing up transactions and make sure all above a limit are dropped
for i := uint64(1); i <= testTxPoolConfig.AccountQueue; i++ {
if err := pool.AddRemoteSync(transaction(i, 100000, key)); err != nil {
if err := pool.addRemoteSync(transaction(i, 100000, key)); err != nil {
t.Fatalf("tx %d: failed to add transaction: %v", i, err)
}
if len(pool.pending) != 0 {
@ -884,7 +903,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
common.MinGasPrice = big.NewInt(0)
// Reduce the eviction interval to a testable amount
defer func(old time.Duration) { evictionInterval = old }(evictionInterval)
evictionInterval = time.Second
evictionInterval = time.Millisecond * 100
// Create the pool to test the non-expiration enforcement
db := rawdb.NewMemoryDatabase()
@ -922,6 +941,22 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Allow the eviction interval to run
time.Sleep(2 * evictionInterval)
// Transactions should not be evicted from the queue yet since lifetime duration has not passed
pending, queued = pool.Stats()
if pending != 0 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
}
if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Wait a bit for eviction to run and clean up any leftovers, and ensure only the local remains
time.Sleep(2 * config.Lifetime)
@ -941,6 +976,72 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// remove current transactions and increase nonce to prepare for a reset and cleanup
statedb.SetNonce(crypto.PubkeyToAddress(remote.PublicKey), 2)
statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 2)
<-pool.requestReset(nil, nil)
// make sure queue, pending are cleared
pending, queued = pool.Stats()
if pending != 0 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 0)
}
if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Queue gapped transactions
if err := pool.AddLocal(pricedTransaction(4, 100000, big.NewInt(1), local)); err != nil {
t.Fatalf("failed to add remote transaction: %v", err)
}
if err := pool.addRemoteSync(pricedTransaction(4, 100000, big.NewInt(1), remote)); err != nil {
t.Fatalf("failed to add remote transaction: %v", err)
}
time.Sleep(5 * evictionInterval) // A half lifetime pass
// Queue executable transactions, the life cycle should be restarted.
if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil {
t.Fatalf("failed to add remote transaction: %v", err)
}
if err := pool.addRemoteSync(pricedTransaction(2, 100000, big.NewInt(1), remote)); err != nil {
t.Fatalf("failed to add remote transaction: %v", err)
}
time.Sleep(6 * evictionInterval)
// All gapped transactions shouldn't be kicked out
pending, queued = pool.Stats()
if pending != 2 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
}
if queued != 2 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 3)
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
// The whole life time pass after last promotion, kick out stale transactions
time.Sleep(2 * config.Lifetime)
pending, queued = pool.Stats()
if pending != 2 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
}
if nolocals {
if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
}
} else {
if queued != 1 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 1)
}
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
}
// Tests that even if the transaction count belonging to a single account goes
@ -953,7 +1054,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
testTxPoolConfig.AccountQueue = 10
// Keep track of transaction events to ensure all executables get announced
@ -963,7 +1064,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
// Keep queuing up transactions and make sure all above a limit are dropped
for i := uint64(0); i < testTxPoolConfig.AccountQueue; i++ {
if err := pool.AddRemoteSync(transaction(i, 100000, key)); err != nil {
if err := pool.addRemoteSync(transaction(i, 100000, key)); err != nil {
t.Fatalf("tx %d: failed to add transaction: %v", i, err)
}
if pool.pending[account].Len() != int(i)+1 {
@ -1033,6 +1134,62 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
}
}
// Test the limit on transaction size is enforced correctly.
// This test verifies every transaction having allowed size
// is added to the pool, and longer transactions are rejected.
func TestTransactionAllowedTxSize(t *testing.T) {
t.Parallel()
// Create a test account and fund it
pool, key := setupTxPool()
defer pool.Stop()
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000000))
// Compute maximal data size for transactions (lower bound).
//
// It is assumed the fields in the transaction (except of the data) are:
// - nonce <= 32 bytes
// - gasPrice <= 32 bytes
// - gasLimit <= 32 bytes
// - recipient == 20 bytes
// - value <= 32 bytes
// - signature == 65 bytes
// All those fields are summed up to at most 213 bytes.
baseSize := uint64(213)
dataSize := txMaxSize - baseSize
// Try adding a transaction with maximal allowed size
tx := pricedDataTransaction(0, pool.currentMaxGas, big.NewInt(1), key, dataSize)
if err := pool.addRemoteSync(tx); err != nil {
t.Fatalf("failed to add transaction of size %d, close to maximal: %v", int(tx.Size()), err)
}
// Try adding a transaction with random allowed size
if err := pool.addRemoteSync(pricedDataTransaction(1, pool.currentMaxGas, big.NewInt(1), key, uint64(rand.Intn(int(dataSize))))); err != nil {
t.Fatalf("failed to add transaction of random allowed size: %v", err)
}
// Try adding a transaction of minimal not allowed size
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, txMaxSize)); err == nil {
t.Fatalf("expected rejection on slightly oversize transaction")
}
// Try adding a transaction of random not allowed size
if err := pool.addRemoteSync(pricedDataTransaction(2, pool.currentMaxGas, big.NewInt(1), key, dataSize+1+uint64(rand.Intn(int(10*txMaxSize))))); err == nil {
t.Fatalf("expected rejection on oversize transaction")
}
// Run some sanity checks on the pool internals
pending, queued := pool.Stats()
if pending != 2 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
}
if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
}
// Tests that if transactions start being capped, transactions are also removed from 'all'
func TestTransactionCapClearsFromAll(t *testing.T) {
t.Parallel()
@ -1458,7 +1615,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
t.Fatalf("pool internal state corrupted: %v", err)
}
// Ensure that adding high priced transactions drops a cheap, but doesn't produce a gap
if err := pool.AddRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil {
t.Fatalf("failed to add well priced transaction: %v", err)
}
pending, queued = pool.Stats()
@ -1476,6 +1633,71 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
}
}
// Tests that the pool rejects duplicate transactions.
func TestTransactionDeduplication(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
defer pool.Stop()
// Create a test account to add transactions with
key, _ := crypto.GenerateKey()
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(1000000000))
// Create a batch of transactions and add a few of them
txs := make([]*types.Transaction, common.LimitThresholdNonceInQueue)
for i := 0; i < len(txs); i++ {
txs[i] = pricedTransaction(uint64(i), 100000, big.NewInt(1), key)
}
var firsts []*types.Transaction
for i := 0; i < len(txs); i += 2 {
firsts = append(firsts, txs[i])
}
errs := pool.AddRemotesSync(firsts)
if len(errs) != len(firsts) {
t.Fatalf("first add mismatching result count: have %d, want %d", len(errs), len(firsts))
}
for i, err := range errs {
if err != nil {
t.Errorf("add %d failed: %v", i, err)
}
}
pending, queued := pool.Stats()
if pending != 1 {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 1)
}
if queued != len(txs)/2-1 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, len(txs)/2-1)
}
// Try to add all of them now and ensure previous ones error out as knowns
errs = pool.AddRemotesSync(txs)
if len(errs) != len(txs) {
t.Fatalf("all add mismatching result count: have %d, want %d", len(errs), len(txs))
}
for i, err := range errs {
if i%2 == 0 && err == nil {
t.Errorf("add %d succeeded, should have failed as known", i)
}
if i%2 == 1 && err != nil {
t.Errorf("add %d failed: %v", i, err)
}
}
pending, queued = pool.Stats()
if pending != len(txs) {
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, len(txs))
}
if queued != 0 {
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 0)
}
if err := validateTxPoolInternals(pool); err != nil {
t.Fatalf("pool internal state corrupted: %v", err)
}
}
// Tests that the pool rejects replacement transactions that don't meet the minimum
// price bump required.
func TestTransactionReplacement(t *testing.T) {
@ -1502,7 +1724,7 @@ func TestTransactionReplacement(t *testing.T) {
price := int64(100)
threshold := (price * (100 + int64(testTxPoolConfig.PriceBump))) / 100
if err := pool.AddRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil {
t.Fatalf("failed to add original cheap pending transaction: %v", err)
}
if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced {
@ -1515,7 +1737,7 @@ func TestTransactionReplacement(t *testing.T) {
t.Fatalf("cheap replacement event firing failed: %v", err)
}
if err := pool.AddRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil {
t.Fatalf("failed to add original proper pending transaction: %v", err)
}
if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced {
@ -1606,7 +1828,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil {
t.Fatalf("failed to add local transaction: %v", err)
}
if err := pool.AddRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil {
if err := pool.addRemoteSync(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil {
t.Fatalf("failed to add remote transaction: %v", err)
}
pending, queued := pool.Stats()
@ -1728,6 +1950,24 @@ func TestTransactionStatusCheck(t *testing.T) {
}
}
// Test the transaction slots consumption is computed correctly
func TestTransactionSlotCount(t *testing.T) {
t.Parallel()
key, _ := crypto.GenerateKey()
// Check that an empty transaction consumes a single slot
smallTx := pricedDataTransaction(0, 0, big.NewInt(0), key, 0)
if slots := numSlots(smallTx); slots != 1 {
t.Fatalf("small transactions slot count mismatch: have %d want %d", slots, 1)
}
// Check that a large transaction consumes the correct number of slots
bigTx := pricedDataTransaction(0, 0, big.NewInt(0), key, uint64(10*txSlotSize))
if slots := numSlots(bigTx); slots != 11 {
t.Fatalf("big transactions slot count mismatch: have %d want %d", slots, 11)
}
}
// Benchmarks the speed of validating the contents of the pending queue of the
// transaction pool.
func BenchmarkPendingDemotion100(b *testing.B) { benchmarkPendingDemotion(b, 100) }
@ -1739,7 +1979,7 @@ func benchmarkPendingDemotion(b *testing.B, size int) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
for i := 0; i < size; i++ {
@ -1764,12 +2004,12 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
for i := 0; i < size; i++ {
tx := transaction(uint64(1+i), 100000, key)
pool.enqueueTx(tx.Hash(), tx)
pool.enqueueTx(tx.Hash(), tx, false, true)
}
// Benchmark the speed of pool validation
b.ResetTimer()
@ -1779,16 +2019,20 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
}
// Benchmarks the speed of batched transaction insertion.
func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100) }
func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000) }
func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000) }
func BenchmarkPoolBatchInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, false) }
func BenchmarkPoolBatchInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, false) }
func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, false) }
func benchmarkPoolBatchInsert(b *testing.B, size int) {
func BenchmarkPoolBatchLocalInsert100(b *testing.B) { benchmarkPoolBatchInsert(b, 100, true) }
func BenchmarkPoolBatchLocalInsert1000(b *testing.B) { benchmarkPoolBatchInsert(b, 1000, true) }
func BenchmarkPoolBatchLocalInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 10000, true) }
func benchmarkPoolBatchInsert(b *testing.B, size int, local bool) {
// Generate a batch of transactions to enqueue into the pool
pool, key := setupTxPool()
defer pool.Stop()
account, _ := deriveSender(transaction(0, 0, key))
account := crypto.PubkeyToAddress(key.PublicKey)
pool.currentState.AddBalance(account, big.NewInt(1000000))
batches := make([]types.Transactions, b.N)
@ -1801,6 +2045,45 @@ func benchmarkPoolBatchInsert(b *testing.B, size int) {
// Benchmark importing the transactions into the queue
b.ResetTimer()
for _, batch := range batches {
pool.AddRemotes(batch)
if local {
pool.AddLocals(batch)
} else {
pool.AddRemotes(batch)
}
}
}
func BenchmarkInsertRemoteWithAllLocals(b *testing.B) {
// Allocate keys for testing
key, _ := crypto.GenerateKey()
account := crypto.PubkeyToAddress(key.PublicKey)
remoteKey, _ := crypto.GenerateKey()
remoteAddr := crypto.PubkeyToAddress(remoteKey.PublicKey)
locals := make([]*types.Transaction, 4096+1024) // Occupy all slots
for i := 0; i < len(locals); i++ {
locals[i] = transaction(uint64(i), 100000, key)
}
remotes := make([]*types.Transaction, 1000)
for i := 0; i < len(remotes); i++ {
remotes[i] = pricedTransaction(uint64(i), 100000, big.NewInt(2), remoteKey) // Higher gasprice
}
// Benchmark importing the transactions into the queue
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StopTimer()
pool, _ := setupTxPool()
pool.currentState.AddBalance(account, big.NewInt(100000000))
for _, local := range locals {
pool.AddLocal(local)
}
b.StartTimer()
// Assign a high enough balance for testing
pool.currentState.AddBalance(remoteAddr, big.NewInt(100000000))
for i := 0; i < len(remotes); i++ {
pool.AddRemotes([]*types.Transaction{remotes[i]})
}
pool.Stop()
}
}

View file

@ -0,0 +1,115 @@
// Copyright 2020 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 types
import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
)
//go:generate gencodec -type AccessTuple -out gen_access_tuple.go
// AccessList is an EIP-2930 access list.
type AccessList []AccessTuple
// AccessTuple is the element type of an access list.
type AccessTuple struct {
Address common.Address `json:"address" gencodec:"required"`
StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"`
}
// StorageKeys returns the total number of storage keys in the access list.
func (al AccessList) StorageKeys() int {
sum := 0
for _, tuple := range al {
sum += len(tuple.StorageKeys)
}
return sum
}
// AccessListTx is the data of EIP-2930 access list transactions.
type AccessListTx struct {
ChainID *big.Int // destination chain ID
Nonce uint64 // nonce of sender account
GasPrice *big.Int // wei per gas
Gas uint64 // gas limit
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int // wei amount
Data []byte // contract invocation input data
AccessList AccessList // EIP-2930 access list
V, R, S *big.Int // signature values
}
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *AccessListTx) copy() TxData {
cpy := &AccessListTx{
Nonce: tx.Nonce,
To: tx.To, // TODO: copy pointed-to address
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
// These are copied below.
AccessList: make(AccessList, len(tx.AccessList)),
Value: new(big.Int),
ChainID: new(big.Int),
GasPrice: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
copy(cpy.AccessList, tx.AccessList)
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.ChainID != nil {
cpy.ChainID.Set(tx.ChainID)
}
if tx.GasPrice != nil {
cpy.GasPrice.Set(tx.GasPrice)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}
// accessors for innerTx.
func (tx *AccessListTx) txType() byte { return AccessListTxType }
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
func (tx *AccessListTx) protected() bool { return true }
func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
func (tx *AccessListTx) data() []byte { return tx.Data }
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
func (tx *AccessListTx) gasPrice() *big.Int { return tx.GasPrice }
func (tx *AccessListTx) value() *big.Int { return tx.Value }
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
func (tx *AccessListTx) to() *common.Address { return tx.To }
func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}
func (tx *AccessListTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}

View file

@ -29,7 +29,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
@ -155,13 +154,6 @@ func (h *Header) Size() common.StorageSize {
return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+h.Time.BitLen())/8)
}
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)
hw.Sum(h[:0])
return h
}
// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
type Body struct {

View file

@ -17,13 +17,18 @@
package types
import (
"bytes"
"hash"
"math/big"
"reflect"
"testing"
"bytes"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
"reflect"
"golang.org/x/crypto/sha3"
)
// from bcValidBlockTest.json, "SimpleTx"
@ -59,3 +64,152 @@ func TestBlockEncoding(t *testing.T) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
}
}
func TestEIP2718BlockEncoding(t *testing.T) {
blockEnc := common.FromHex("f9031cf90214a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4808080f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c0")
var block Block
if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
t.Fatal("decode error: ", err)
}
check := func(f string, got, want interface{}) {
if !reflect.DeepEqual(got, want) {
t.Errorf("%s mismatch: got %v, want %v", f, got, want)
}
}
check("Difficulty", block.Difficulty(), big.NewInt(131072))
check("GasLimit", block.GasLimit(), uint64(3141592))
check("GasUsed", block.GasUsed(), uint64(42000))
check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
check("Time", block.Time().Uint64(), uint64(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
// Create legacy tx.
to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
tx1 := NewTx(&LegacyTx{
Nonce: 0,
To: &to,
Value: big.NewInt(10),
Gas: 50000,
GasPrice: big.NewInt(10),
})
sig := common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")
tx1, _ = tx1.WithSignature(HomesteadSigner{}, sig)
// Create ACL tx.
addr := common.HexToAddress("0x0000000000000000000000000000000000000001")
tx2 := NewTx(&AccessListTx{
ChainID: big.NewInt(1),
Nonce: 0,
To: &to,
Gas: 123457,
GasPrice: big.NewInt(10),
AccessList: AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}},
})
sig2 := common.Hex2Bytes("3dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef1401")
tx2, _ = tx2.WithSignature(NewEIP2930Signer(big.NewInt(1)), sig2)
check("len(Transactions)", len(block.Transactions()), 2)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash())
check("Transactions[1].Type()", block.Transactions()[1].Type(), uint8(AccessListTxType))
ourBlockEnc, err := rlp.EncodeToBytes(&block)
if err != nil {
t.Fatal("encode error: ", err)
}
if !bytes.Equal(ourBlockEnc, blockEnc) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
}
}
func TestUncleHash(t *testing.T) {
uncles := make([]*Header, 0)
h := CalcUncleHash(uncles)
exp := common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")
if h != exp {
t.Fatalf("empty uncle hash is wrong, got %x != %x", h, exp)
}
}
var benchBuffer = bytes.NewBuffer(make([]byte, 0, 32000))
func BenchmarkEncodeBlock(b *testing.B) {
block := makeBenchBlock()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchBuffer.Reset()
if err := rlp.Encode(benchBuffer, block); err != nil {
b.Fatal(err)
}
}
}
// testHasher is the helper tool for transaction/receipt list hashing.
// The original hasher is trie, in order to get rid of import cycle,
// use the testing hasher instead.
type testHasher struct {
hasher hash.Hash
}
func newHasher() *testHasher {
return &testHasher{hasher: sha3.NewLegacyKeccak256()}
}
func (h *testHasher) Reset() {
h.hasher.Reset()
}
func (h *testHasher) Update(key, val []byte) {
h.hasher.Write(key)
h.hasher.Write(val)
}
func (h *testHasher) Hash() common.Hash {
return common.BytesToHash(h.hasher.Sum(nil))
}
func makeBenchBlock() *Block {
var (
key, _ = crypto.GenerateKey()
txs = make([]*Transaction, 70)
receipts = make([]*Receipt, len(txs))
signer = LatestSigner(params.TestChainConfig)
uncles = make([]*Header, 3)
)
header := &Header{
Difficulty: math.BigPow(11, 11),
Number: math.BigPow(2, 9),
GasLimit: 12345678,
GasUsed: 1476322,
Time: big.NewInt(9876543),
Extra: []byte("coolest block on chain"),
}
for i := range txs {
amount := math.BigPow(2, int64(i))
price := big.NewInt(300000)
data := make([]byte, 100)
tx := NewTransaction(uint64(i), common.Address{}, amount, 123457, price, data)
signedTx, err := SignTx(tx, signer, key)
if err != nil {
panic(err)
}
txs[i] = signedTx
receipts[i] = NewReceipt(make([]byte, 32), false, tx.Gas())
}
for i := range uncles {
uncles[i] = &Header{
Difficulty: math.BigPow(11, 11),
Number: math.BigPow(2, 9),
GasLimit: 12345678,
GasUsed: 1476322,
Time: big.NewInt(9876543),
Extra: []byte("benchmark uncle"),
}
}
return NewBlock(header, txs, uncles, receipts)
}

View file

@ -1,6 +1,7 @@
package types
import (
"errors"
"fmt"
"math/big"
"reflect"
@ -15,11 +16,11 @@ import (
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
func DecodeBytesExtraFields(b []byte, val interface{}) error {
if len(b) == 0 {
return fmt.Errorf("extra field is 0 length")
return errors.New("extra field is 0 length")
}
switch b[0] {
case 1:
return fmt.Errorf("consensus version 1 is not applicable for decoding extra fields")
return errors.New("consensus version 1 is not applicable for decoding extra fields")
case 2:
return rlp.DecodeBytes(b[1:], val)
default:

View file

@ -0,0 +1,43 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/XinFinOrg/XDPoSChain/common"
)
// MarshalJSON marshals as JSON.
func (a AccessTuple) MarshalJSON() ([]byte, error) {
type AccessTuple struct {
Address common.Address `json:"address" gencodec:"required"`
StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"`
}
var enc AccessTuple
enc.Address = a.Address
enc.StorageKeys = a.StorageKeys
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (a *AccessTuple) UnmarshalJSON(input []byte) error {
type AccessTuple struct {
Address *common.Address `json:"address" gencodec:"required"`
StorageKeys []common.Hash `json:"storageKeys" gencodec:"required"`
}
var dec AccessTuple
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Address == nil {
return errors.New("missing required field 'address' for AccessTuple")
}
a.Address = *dec.Address
if dec.StorageKeys == nil {
return errors.New("missing required field 'storageKeys' for AccessTuple")
}
a.StorageKeys = dec.StorageKeys
return nil
}

View file

@ -13,8 +13,10 @@ import (
var _ = (*receiptMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (r Receipt) MarshalJSON() ([]byte, error) {
type Receipt struct {
Type hexutil.Uint64 `json:"type,omitempty"`
PostState hexutil.Bytes `json:"root"`
Status hexutil.Uint `json:"status"`
CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@ -28,6 +30,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
TransactionIndex hexutil.Uint `json:"transactionIndex"`
}
var enc Receipt
enc.Type = hexutil.Uint64(r.Type)
enc.PostState = r.PostState
enc.Status = hexutil.Uint(r.Status)
enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed)
@ -42,8 +45,10 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (r *Receipt) UnmarshalJSON(input []byte) error {
type Receipt struct {
Type *hexutil.Uint64 `json:"type,omitempty"`
PostState *hexutil.Bytes `json:"root"`
Status *hexutil.Uint `json:"status"`
CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@ -60,6 +65,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Type != nil {
r.Type = uint8(*dec.Type)
}
if dec.PostState != nil {
r.PostState = *dec.PostState
}

View file

@ -1,101 +0,0 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
)
var _ = (*txdataMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (t txdata) MarshalJSON() ([]byte, error) {
type txdata struct {
AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"`
Amount *hexutil.Big `json:"value" gencodec:"required"`
Payload hexutil.Bytes `json:"input" gencodec:"required"`
V *hexutil.Big `json:"v" gencodec:"required"`
R *hexutil.Big `json:"r" gencodec:"required"`
S *hexutil.Big `json:"s" gencodec:"required"`
Hash *common.Hash `json:"hash" rlp:"-"`
}
var enc txdata
enc.AccountNonce = hexutil.Uint64(t.AccountNonce)
enc.Price = (*hexutil.Big)(t.Price)
enc.GasLimit = hexutil.Uint64(t.GasLimit)
enc.Recipient = t.Recipient
enc.Amount = (*hexutil.Big)(t.Amount)
enc.Payload = t.Payload
enc.V = (*hexutil.Big)(t.V)
enc.R = (*hexutil.Big)(t.R)
enc.S = (*hexutil.Big)(t.S)
enc.Hash = t.Hash
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (t *txdata) UnmarshalJSON(input []byte) error {
type txdata struct {
AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
Price *hexutil.Big `json:"gasPrice" gencodec:"required"`
GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"`
Amount *hexutil.Big `json:"value" gencodec:"required"`
Payload *hexutil.Bytes `json:"input" gencodec:"required"`
V *hexutil.Big `json:"v" gencodec:"required"`
R *hexutil.Big `json:"r" gencodec:"required"`
S *hexutil.Big `json:"s" gencodec:"required"`
Hash *common.Hash `json:"hash" rlp:"-"`
}
var dec txdata
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.AccountNonce == nil {
return errors.New("missing required field 'nonce' for txdata")
}
t.AccountNonce = uint64(*dec.AccountNonce)
if dec.Price == nil {
return errors.New("missing required field 'gasPrice' for txdata")
}
t.Price = (*big.Int)(dec.Price)
if dec.GasLimit == nil {
return errors.New("missing required field 'gas' for txdata")
}
t.GasLimit = uint64(*dec.GasLimit)
if dec.Recipient != nil {
t.Recipient = dec.Recipient
}
if dec.Amount == nil {
return errors.New("missing required field 'value' for txdata")
}
t.Amount = (*big.Int)(dec.Amount)
if dec.Payload == nil {
return errors.New("missing required field 'input' for txdata")
}
t.Payload = *dec.Payload
if dec.V == nil {
return errors.New("missing required field 'v' for txdata")
}
t.V = (*big.Int)(dec.V)
if dec.R == nil {
return errors.New("missing required field 'r' for txdata")
}
t.R = (*big.Int)(dec.R)
if dec.S == nil {
return errors.New("missing required field 's' for txdata")
}
t.S = (*big.Int)(dec.S)
if dec.Hash != nil {
t.Hash = dec.Hash
}
return nil
}

59
core/types/hashing.go Normal file
View file

@ -0,0 +1,59 @@
// Copyright 2014 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 types
import (
"bytes"
"sync"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/rlp"
"golang.org/x/crypto/sha3"
)
// hasherPool holds LegacyKeccak256 hashers for rlpHash.
var hasherPool = sync.Pool{
New: func() interface{} { return sha3.NewLegacyKeccak256() },
}
// deriveBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
var encodeBufferPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
// rlpHash encodes x and hashes the encoded bytes.
func rlpHash(x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
rlp.Encode(sha, x)
sha.Read(h[:])
return h
}
// prefixedRlpHash writes the prefix into the hasher before rlp-encoding x.
// It's used for typed transactions.
func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
sha.Write([]byte{prefix})
rlp.Encode(sha, x)
sha.Read(h[:])
return h
}

111
core/types/legacy_tx.go Normal file
View file

@ -0,0 +1,111 @@
// Copyright 2020 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 types
import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
)
// LegacyTx is the transaction data of regular Ethereum transactions.
type LegacyTx struct {
Nonce uint64 // nonce of sender account
GasPrice *big.Int // wei per gas
Gas uint64 // gas limit
To *common.Address `rlp:"nil"` // nil means contract creation
Value *big.Int // wei amount
Data []byte // contract invocation input data
V, R, S *big.Int // signature values
}
// NewTransaction creates an unsigned legacy transaction.
// Deprecated: use NewTx instead.
func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return NewTx(&LegacyTx{
Nonce: nonce,
To: &to,
Value: amount,
Gas: gasLimit,
GasPrice: gasPrice,
Data: data,
})
}
// NewContractCreation creates an unsigned legacy transaction.
// Deprecated: use NewTx instead.
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return NewTx(&LegacyTx{
Nonce: nonce,
Value: amount,
Gas: gasLimit,
GasPrice: gasPrice,
Data: data,
})
}
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *LegacyTx) copy() TxData {
cpy := &LegacyTx{
Nonce: tx.Nonce,
To: tx.To, // TODO: copy pointed-to address
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
// These are initialized below.
Value: new(big.Int),
GasPrice: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
if tx.Value != nil {
cpy.Value.Set(tx.Value)
}
if tx.GasPrice != nil {
cpy.GasPrice.Set(tx.GasPrice)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}
// accessors for innerTx.
func (tx *LegacyTx) txType() byte { return LegacyTxType }
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
func (tx *LegacyTx) accessList() AccessList { return nil }
func (tx *LegacyTx) data() []byte { return tx.Data }
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
func (tx *LegacyTx) gasPrice() *big.Int { return tx.GasPrice }
func (tx *LegacyTx) value() *big.Int { return tx.Value }
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
func (tx *LegacyTx) to() *common.Address { return tx.To }
func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}
func (tx *LegacyTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.V, tx.R, tx.S = v, r, s
}

View file

@ -18,7 +18,7 @@ package types
import (
"encoding/json"
"fmt"
"errors"
"reflect"
"testing"
@ -97,7 +97,7 @@ var unmarshalLogTests = map[string]struct {
},
"missing data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
wantError: fmt.Errorf("missing required field 'data' for Log"),
wantError: errors.New("missing required field 'data' for Log"),
},
}

View file

@ -18,6 +18,7 @@ package types
import (
"bytes"
"errors"
"fmt"
"io"
"math/big"
@ -35,6 +36,9 @@ var (
receiptStatusSuccessfulRLP = []byte{0x01}
)
// This error is returned when a typed receipt is decoded, but the string is empty.
var errEmptyTypedReceipt = errors.New("empty typed receipt bytes")
const (
// ReceiptStatusFailed is the status code of a transaction if execution failed.
ReceiptStatusFailed = uint(0)
@ -46,6 +50,7 @@ const (
// Receipt represents the results of a transaction.
type Receipt struct {
// Consensus fields: These fields are defined by the Yellow Paper
Type uint8 `json:"type,omitempty"`
PostState []byte `json:"root"`
Status uint `json:"status"`
CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
@ -66,6 +71,7 @@ type Receipt struct {
}
type receiptMarshaling struct {
Type hexutil.Uint64
PostState hexutil.Bytes
Status hexutil.Uint
CumulativeGasUsed hexutil.Uint64
@ -82,7 +88,18 @@ type receiptRLP struct {
Logs []*Log
}
type receiptStorageRLP struct {
// v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
type v4StoredReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
TxHash common.Hash
ContractAddress common.Address
Logs []*LogForStorage
GasUsed uint64
}
// v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields.
type v3StoredReceiptRLP struct {
PostStateOrStatus []byte
CumulativeGasUsed uint64
Bloom Bloom
@ -93,8 +110,13 @@ type receiptStorageRLP struct {
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
// Deprecated: create receipts using a struct literal instead.
func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed}
r := &Receipt{
Type: LegacyTxType,
PostState: common.CopyBytes(root),
CumulativeGasUsed: cumulativeGasUsed,
}
if failed {
r.Status = ReceiptStatusFailed
} else {
@ -106,21 +128,65 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream. If no post state is present, byzantium fork is assumed.
func (r *Receipt) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
if r.Type == LegacyTxType {
return rlp.Encode(w, data)
}
// It's an EIP-2718 typed TX receipt.
if r.Type != AccessListTxType {
return ErrTxTypeNotSupported
}
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()
buf.WriteByte(r.Type)
if err := rlp.Encode(buf, data); err != nil {
return err
}
return rlp.Encode(w, buf.Bytes())
}
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
var dec receiptRLP
if err := s.Decode(&dec); err != nil {
kind, _, err := s.Kind()
switch {
case err != nil:
return err
case kind == rlp.List:
// It's a legacy receipt.
var dec receiptRLP
if err := s.Decode(&dec); err != nil {
return err
}
r.Type = LegacyTxType
return r.setFromRLP(dec)
case kind == rlp.String:
// It's an EIP-2718 typed tx receipt.
b, err := s.Bytes()
if err != nil {
return err
}
if len(b) == 0 {
return errEmptyTypedReceipt
}
r.Type = b[0]
if r.Type == AccessListTxType {
var dec receiptRLP
if err := rlp.DecodeBytes(b[1:], &dec); err != nil {
return err
}
return r.setFromRLP(dec)
}
return ErrTxTypeNotSupported
default:
return rlp.ErrExpectedList
}
if err := r.setStatus(dec.PostStateOrStatus); err != nil {
return err
}
r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
return nil
}
func (r *Receipt) setFromRLP(data receiptRLP) error {
r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs
return r.setStatus(data.PostStateOrStatus)
}
func (r *Receipt) setStatus(postStateOrStatus []byte) error {
@ -151,7 +217,6 @@ func (r *Receipt) statusEncoding() []byte {
// to approximate and limit the memory consumption of various caches.
func (r *Receipt) Size() common.StorageSize {
size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
for _, log := range r.Logs {
size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
@ -174,7 +239,7 @@ type ReceiptForStorage Receipt
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
// into an RLP stream.
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
enc := &receiptStorageRLP{
enc := &v3StoredReceiptRLP{
PostStateOrStatus: (*Receipt)(r).statusEncoding(),
CumulativeGasUsed: r.CumulativeGasUsed,
Bloom: r.Bloom,
@ -192,25 +257,64 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
var dec receiptStorageRLP
if err := s.Decode(&dec); err != nil {
// Retrieve the entire receipt blob as we need to try multiple decoders
blob, err := s.Raw()
if err != nil {
return err
}
if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
// Try decoding from the newest format for future proofness, then the older one
// for old nodes that just upgraded. V4 was an intermediate unreleased format so
// we do need to decode it, but it's not common (try last).
if err := decodeV3StoredReceiptRLP(r, blob); err == nil {
return nil
}
return decodeV4StoredReceiptRLP(r, blob)
}
func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
var stored v3StoredReceiptRLP
if err := rlp.DecodeBytes(blob, &stored); err != nil {
return err
}
if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
return err
}
// Assign the consensus fields
r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
r.Logs = make([]*Log, len(dec.Logs))
for i, log := range dec.Logs {
r.CumulativeGasUsed = stored.CumulativeGasUsed
r.Bloom = stored.Bloom
r.Logs = make([]*Log, len(stored.Logs))
for i, log := range stored.Logs {
r.Logs[i] = (*Log)(log)
}
// Assign the implementation fields
r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
r.TxHash = stored.TxHash
r.ContractAddress = stored.ContractAddress
r.GasUsed = stored.GasUsed
return nil
}
// Receipts is a wrapper around a Receipt array to implement DerivableList.
func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
var stored v4StoredReceiptRLP
if err := rlp.DecodeBytes(blob, &stored); err != nil {
return err
}
if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
return err
}
r.CumulativeGasUsed = stored.CumulativeGasUsed
r.TxHash = stored.TxHash
r.ContractAddress = stored.ContractAddress
r.GasUsed = stored.GasUsed
r.Logs = make([]*Log, len(stored.Logs))
for i, log := range stored.Logs {
r.Logs[i] = (*Log)(log)
}
r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
return nil
}
// Receipts implements DerivableList for receipts.
type Receipts []*Receipt
// Len returns the number of receipts in this list.

170
core/types/receipt_test.go Normal file
View file

@ -0,0 +1,170 @@
// 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 types
import (
"bytes"
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
func TestDecodeEmptyTypedReceipt(t *testing.T) {
input := []byte{0x80}
var r Receipt
err := rlp.DecodeBytes(input, &r)
if err != errEmptyTypedReceipt {
t.Fatal("wrong error:", err)
}
}
func TestLegacyReceiptDecoding(t *testing.T) {
tests := []struct {
name string
encode func(*Receipt) ([]byte, error)
}{
{
"V4StoredReceiptRLP",
encodeAsV4StoredReceiptRLP,
},
{
"V3StoredReceiptRLP",
encodeAsV3StoredReceiptRLP,
},
}
tx := NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
receipt := &Receipt{
Status: ReceiptStatusFailed,
CumulativeGasUsed: 1,
Logs: []*Log{
{
Address: common.BytesToAddress([]byte{0x11}),
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
{
Address: common.BytesToAddress([]byte{0x01, 0x11}),
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
Data: []byte{0x01, 0x00, 0xff},
},
},
TxHash: tx.Hash(),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
GasUsed: 111111,
}
receipt.Bloom = CreateBloom(Receipts{receipt})
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
enc, err := tc.encode(receipt)
if err != nil {
t.Fatalf("Error encoding receipt: %v", err)
}
var dec ReceiptForStorage
if err := rlp.DecodeBytes(enc, &dec); err != nil {
t.Fatalf("Error decoding RLP receipt: %v", err)
}
// Check whether all consensus fields are correct.
if dec.Status != receipt.Status {
t.Fatalf("Receipt status mismatch, want %v, have %v", receipt.Status, dec.Status)
}
if dec.CumulativeGasUsed != receipt.CumulativeGasUsed {
t.Fatalf("Receipt CumulativeGasUsed mismatch, want %v, have %v", receipt.CumulativeGasUsed, dec.CumulativeGasUsed)
}
if dec.Bloom != receipt.Bloom {
t.Fatalf("Bloom data mismatch, want %v, have %v", receipt.Bloom, dec.Bloom)
}
if len(dec.Logs) != len(receipt.Logs) {
t.Fatalf("Receipt log number mismatch, want %v, have %v", len(receipt.Logs), len(dec.Logs))
}
for i := 0; i < len(dec.Logs); i++ {
if dec.Logs[i].Address != receipt.Logs[i].Address {
t.Fatalf("Receipt log %d address mismatch, want %v, have %v", i, receipt.Logs[i].Address, dec.Logs[i].Address)
}
if !reflect.DeepEqual(dec.Logs[i].Topics, receipt.Logs[i].Topics) {
t.Fatalf("Receipt log %d topics mismatch, want %v, have %v", i, receipt.Logs[i].Topics, dec.Logs[i].Topics)
}
if !bytes.Equal(dec.Logs[i].Data, receipt.Logs[i].Data) {
t.Fatalf("Receipt log %d data mismatch, want %v, have %v", i, receipt.Logs[i].Data, dec.Logs[i].Data)
}
}
})
}
}
func encodeAsV4StoredReceiptRLP(want *Receipt) ([]byte, error) {
stored := &v4StoredReceiptRLP{
PostStateOrStatus: want.statusEncoding(),
CumulativeGasUsed: want.CumulativeGasUsed,
TxHash: want.TxHash,
ContractAddress: want.ContractAddress,
Logs: make([]*LogForStorage, len(want.Logs)),
GasUsed: want.GasUsed,
}
for i, log := range want.Logs {
stored.Logs[i] = (*LogForStorage)(log)
}
return rlp.EncodeToBytes(stored)
}
func encodeAsV3StoredReceiptRLP(want *Receipt) ([]byte, error) {
stored := &v3StoredReceiptRLP{
PostStateOrStatus: want.statusEncoding(),
CumulativeGasUsed: want.CumulativeGasUsed,
Bloom: want.Bloom,
TxHash: want.TxHash,
ContractAddress: want.ContractAddress,
Logs: make([]*LogForStorage, len(want.Logs)),
GasUsed: want.GasUsed,
}
for i, log := range want.Logs {
stored.Logs[i] = (*LogForStorage)(log)
}
return rlp.EncodeToBytes(stored)
}
// TestTypedReceiptEncodingDecoding reproduces a flaw that existed in the receipt
// rlp decoder, which failed due to a shadowing error.
func TestTypedReceiptEncodingDecoding(t *testing.T) {
var payload = common.FromHex("f9043eb9010c01f90108018262d4b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0b9010c01f901080182cd14b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0b9010d01f901090183013754b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0b9010d01f90109018301a194b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0")
check := func(bundle []*Receipt) {
t.Helper()
for i, receipt := range bundle {
if got, want := receipt.Type, uint8(1); got != want {
t.Fatalf("bundle %d: got %x, want %x", i, got, want)
}
}
}
{
var bundle []*Receipt
rlp.DecodeBytes(payload, &bundle)
check(bundle)
}
{
var bundle []*Receipt
r := bytes.NewReader(payload)
s := rlp.NewStream(r, uint64(len(payload)))
if err := s.Decode(&bundle); err != nil {
t.Fatal(err)
}
check(bundle)
}
}

View file

@ -24,241 +24,346 @@ import (
"io"
"math/big"
"sync/atomic"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
var (
ErrInvalidSig = errors.New("invalid transaction v, r, s values")
ErrUnexpectedProtection = errors.New("transaction type does not supported EIP-155 protected signatures")
ErrInvalidTxType = errors.New("transaction type not valid in this context")
ErrTxTypeNotSupported = errors.New("transaction type not supported")
ErrGasFeeCapTooLow = errors.New("fee cap less than base fee")
errShortTypedTx = errors.New("typed transaction too short")
errInvalidYParity = errors.New("'yParity' field must be 0 or 1")
errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match")
errVYParityMissing = errors.New("missing 'yParity' or 'v' field in transaction")
errEmptyTypedTx = errors.New("empty typed transaction bytes")
errNoSigner = errors.New("missing signing methods")
skipNonceDestinationAddress = map[string]bool{
common.XDCXAddr: true,
common.TradingStateAddr: true,
common.XDCXLendingAddress: true,
common.XDCXLendingFinalizedTradeAddress: true,
skipNonceDestinationAddress = map[common.Address]bool{
common.XDCXAddrBinary: true,
common.TradingStateAddrBinary: true,
common.XDCXLendingAddressBinary: true,
common.XDCXLendingFinalizedTradeAddressBinary: true,
}
)
// deriveSigner makes a *best* guess about which signer to use.
func deriveSigner(V *big.Int) Signer {
if V.Sign() != 0 && isProtectedV(V) {
return NewEIP155Signer(deriveChainId(V))
} else {
return HomesteadSigner{}
}
}
// Transaction types.
const (
LegacyTxType = iota
AccessListTxType
)
// Transaction is an Ethereum transaction.
type Transaction struct {
data txdata
inner TxData // Consensus contents of a transaction
time time.Time // Time first seen locally (spam avoidance)
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
}
type txdata struct {
AccountNonce uint64 `json:"nonce" gencodec:"required"`
Price *big.Int `json:"gasPrice" gencodec:"required"`
GasLimit uint64 `json:"gas" gencodec:"required"`
Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value" gencodec:"required"`
Payload []byte `json:"input" gencodec:"required"`
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
// This is only used when marshaling to JSON.
Hash *common.Hash `json:"hash" rlp:"-"`
// NewTx creates a new transaction.
func NewTx(inner TxData) *Transaction {
tx := new(Transaction)
tx.setDecoded(inner.copy(), 0)
return tx
}
type txdataMarshaling struct {
AccountNonce hexutil.Uint64
Price *hexutil.Big
GasLimit hexutil.Uint64
Amount *hexutil.Big
Payload hexutil.Bytes
V *hexutil.Big
R *hexutil.Big
S *hexutil.Big
// TxData is the underlying data of a transaction.
//
// This is implemented by LegacyTx and AccessListTx.
type TxData interface {
txType() byte // returns the type ID
copy() TxData // creates a deep copy and initializes all fields
chainID() *big.Int
accessList() AccessList
data() []byte
gas() uint64
gasPrice() *big.Int
value() *big.Int
nonce() uint64
to() *common.Address
rawSignatureValues() (v, r, s *big.Int)
setSignatureValues(chainID, v, r, s *big.Int)
}
func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
}
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
}
func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
if len(data) > 0 {
data = common.CopyBytes(data)
// EncodeRLP implements rlp.Encoder
func (tx *Transaction) EncodeRLP(w io.Writer) error {
if tx.Type() == LegacyTxType {
return rlp.Encode(w, tx.inner)
}
d := txdata{
AccountNonce: nonce,
Recipient: to,
Payload: data,
Amount: new(big.Int),
GasLimit: gasLimit,
Price: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
// It's an EIP-2718 typed TX envelope.
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()
if err := tx.encodeTyped(buf); err != nil {
return err
}
if amount != nil {
d.Amount.Set(amount)
return rlp.Encode(w, buf.Bytes())
}
// encodeTyped writes the canonical encoding of a typed transaction to w.
func (tx *Transaction) encodeTyped(w *bytes.Buffer) error {
w.WriteByte(tx.Type())
return rlp.Encode(w, tx.inner)
}
// MarshalBinary returns the canonical encoding of the transaction.
// For legacy transactions, it returns the RLP encoding. For EIP-2718 typed
// transactions, it returns the type and payload.
func (tx *Transaction) MarshalBinary() ([]byte, error) {
if tx.Type() == LegacyTxType {
return rlp.EncodeToBytes(tx.inner)
}
if gasPrice != nil {
d.Price.Set(gasPrice)
var buf bytes.Buffer
err := tx.encodeTyped(&buf)
return buf.Bytes(), err
}
// DecodeRLP implements rlp.Decoder
func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
kind, size, err := s.Kind()
switch {
case err != nil:
return err
case kind == rlp.List:
// It's a legacy transaction.
var inner LegacyTx
err := s.Decode(&inner)
if err == nil {
tx.setDecoded(&inner, int(rlp.ListSize(size)))
}
return err
case kind == rlp.String:
// It's an EIP-2718 typed TX envelope.
var b []byte
if b, err = s.Bytes(); err != nil {
return err
}
inner, err := tx.decodeTyped(b)
if err == nil {
tx.setDecoded(inner, len(b))
}
return err
default:
return rlp.ErrExpectedList
}
}
// UnmarshalBinary decodes the canonical encoding of transactions.
// It supports legacy RLP transactions and EIP2718 typed transactions.
func (tx *Transaction) UnmarshalBinary(b []byte) error {
if len(b) > 0 && b[0] > 0x7f {
// It's a legacy transaction.
var data LegacyTx
err := rlp.DecodeBytes(b, &data)
if err != nil {
return err
}
tx.setDecoded(&data, len(b))
return nil
}
// It's an EIP2718 typed transaction envelope.
inner, err := tx.decodeTyped(b)
if err != nil {
return err
}
tx.setDecoded(inner, len(b))
return nil
}
// decodeTyped decodes a typed transaction from the canonical format.
func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
if len(b) == 0 {
return nil, errEmptyTypedTx
}
switch b[0] {
case AccessListTxType:
var inner AccessListTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
default:
return nil, ErrTxTypeNotSupported
}
}
// setDecoded sets the inner transaction and size after decoding.
func (tx *Transaction) setDecoded(inner TxData, size int) {
tx.inner = inner
tx.time = time.Now()
if size > 0 {
tx.size.Store(common.StorageSize(size))
}
}
func sanityCheckSignature(v *big.Int, r *big.Int, s *big.Int, maybeProtected bool) error {
if isProtectedV(v) && !maybeProtected {
return ErrUnexpectedProtection
}
return &Transaction{data: d}
}
var plainV byte
if isProtectedV(v) {
chainID := deriveChainId(v).Uint64()
plainV = byte(v.Uint64() - 35 - 2*chainID)
} else if maybeProtected {
// Only EIP-155 signatures can be optionally protected. Since
// we determined this v value is not protected, it must be a
// raw 27 or 28.
plainV = byte(v.Uint64() - 27)
} else {
// If the signature is not optionally protected, we assume it
// must already be equal to the recovery id.
plainV = byte(v.Uint64())
}
if !crypto.ValidateSignatureValues(plainV, r, s, false) {
return ErrInvalidSig
}
// ChainId returns which chain id this transaction was signed for (if at all)
func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V)
}
// Protected returns whether the transaction is protected from replay protection.
func (tx *Transaction) Protected() bool {
return isProtectedV(tx.data.V)
return nil
}
func isProtectedV(V *big.Int) bool {
if V.BitLen() <= 8 {
v := V.Uint64()
return v != 27 && v != 28
return v != 27 && v != 28 && v != 1 && v != 0
}
// anything not 27 or 28 are considered unprotected
// anything not 27 or 28 is considered protected
return true
}
// EncodeRLP implements rlp.Encoder
func (tx *Transaction) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &tx.data)
// Protected says whether the transaction is replay-protected.
func (tx *Transaction) Protected() bool {
switch tx := tx.inner.(type) {
case *LegacyTx:
return tx.V != nil && isProtectedV(tx.V)
default:
return true
}
}
// DecodeRLP implements rlp.Decoder
func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
_, size, _ := s.Kind()
err := s.Decode(&tx.data)
if err == nil {
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
}
return err
// Type returns the transaction type.
func (tx *Transaction) Type() uint8 {
return tx.inner.txType()
}
// MarshalJSON encodes the web3 RPC transaction format.
func (tx *Transaction) MarshalJSON() ([]byte, error) {
hash := tx.Hash()
data := tx.data
data.Hash = &hash
return data.MarshalJSON()
// ChainId returns the EIP155 chain ID of the transaction. The return value will always be
// non-nil. For legacy transactions which are not replay-protected, the return value is
// zero.
func (tx *Transaction) ChainId() *big.Int {
return tx.inner.chainID()
}
// UnmarshalJSON decodes the web3 RPC transaction format.
func (tx *Transaction) UnmarshalJSON(input []byte) error {
var dec txdata
if err := dec.UnmarshalJSON(input); err != nil {
return err
}
var V byte
if isProtectedV(dec.V) {
chainID := deriveChainId(dec.V).Uint64()
V = byte(dec.V.Uint64() - 35 - 2*chainID)
} else {
V = byte(dec.V.Uint64() - 27)
}
if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
return ErrInvalidSig
}
*tx = Transaction{data: dec}
return nil
}
// Data returns the input data of the transaction.
func (tx *Transaction) Data() []byte { return tx.inner.data() }
func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
func (tx *Transaction) CheckNonce() bool { return true }
// AccessList returns the access list of the transaction.
func (tx *Transaction) AccessList() AccessList { return tx.inner.accessList() }
// Gas returns the gas limit of the transaction.
func (tx *Transaction) Gas() uint64 { return tx.inner.gas() }
// GasPrice returns the gas price of the transaction.
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) }
// Value returns the ether amount of the transaction.
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) }
// Nonce returns the sender account nonce of the transaction.
func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() }
// To returns the recipient address of the transaction.
// It returns nil if the transaction is a contract creation.
// For contract-creation transactions, To returns nil.
func (tx *Transaction) To() *common.Address {
if tx.data.Recipient == nil {
// Copy the pointed-to address.
ito := tx.inner.to()
if ito == nil {
return nil
}
to := *tx.data.Recipient
return &to
cpy := *ito
return &cpy
}
func (tx *Transaction) From() *common.Address {
if tx.data.V != nil {
signer := deriveSigner(tx.data.V)
if f, err := Sender(signer, tx); err != nil {
return nil
} else {
return &f
}
var signer Signer
if tx.Protected() {
signer = LatestSignerForChainID(tx.ChainId())
} else {
signer = HomesteadSigner{}
}
from, err := Sender(signer, tx)
if err != nil {
return nil
}
return &from
}
// Hash hashes the RLP encoding of tx.
// It uniquely identifies the transaction.
// RawSignatureValues returns the V, R, S signature values of the transaction.
// The return values should not be modified by the caller.
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
return tx.inner.rawSignatureValues()
}
// GasPriceCmp compares the gas prices of two transactions.
func (tx *Transaction) GasPriceCmp(other *Transaction) int {
return tx.inner.gasPrice().Cmp(other.inner.gasPrice())
}
// GasPriceIntCmp compares the gas price of the transaction against the given price.
func (tx *Transaction) GasPriceIntCmp(other *big.Int) int {
return tx.inner.gasPrice().Cmp(other)
}
// Hash returns the transaction hash.
func (tx *Transaction) Hash() common.Hash {
if hash := tx.hash.Load(); hash != nil {
return hash.(common.Hash)
}
v := rlpHash(tx)
tx.hash.Store(v)
return v
}
func (tx *Transaction) CacheHash() {
v := rlpHash(tx)
tx.hash.Store(v)
var h common.Hash
if tx.Type() == LegacyTxType {
h = rlpHash(tx.inner)
} else {
h = prefixedRlpHash(tx.Type(), tx.inner)
}
tx.hash.Store(h)
return h
}
// Size returns the true RLP encoded storage size of the transaction, either by
// encoding and returning it, or returning a previsouly cached value.
// encoding and returning it, or returning a previously cached value.
func (tx *Transaction) Size() common.StorageSize {
if size := tx.size.Load(); size != nil {
return size.(common.StorageSize)
}
c := writeCounter(0)
rlp.Encode(&c, &tx.data)
rlp.Encode(&c, &tx.inner)
tx.size.Store(common.StorageSize(c))
return common.StorageSize(c)
}
// AsMessage returns the transaction as a core.Message.
//
// AsMessage requires a signer to derive the sender.
//
// XXX Rename message to something less arbitrary?
func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, number *big.Int) (Message, error) {
msg := Message{
nonce: tx.data.AccountNonce,
gasLimit: tx.data.GasLimit,
gasPrice: new(big.Int).Set(tx.data.Price),
to: tx.data.Recipient,
amount: tx.data.Amount,
data: tx.data.Payload,
nonce: tx.Nonce(),
gasLimit: tx.Gas(),
gasPrice: new(big.Int).Set(tx.GasPrice()),
to: tx.To(),
amount: tx.Value(),
data: tx.Data(),
accessList: tx.AccessList(),
checkNonce: true,
balanceTokenFee: balanceFee,
}
var err error
msg.from, err = Sender(s, tx)
if balanceFee != nil {
@ -274,151 +379,94 @@ func (tx *Transaction) AsMessage(s Signer, balanceFee *big.Int, number *big.Int)
}
// WithSignature returns a new transaction with the given signature.
// This signature needs to be formatted as described in the yellow paper (v+27).
// This signature needs to be in the [R || S || V] format where V is 0 or 1.
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
r, s, v, err := signer.SignatureValues(tx, sig)
if err != nil {
return nil, err
}
cpy := &Transaction{data: tx.data}
cpy.data.R, cpy.data.S, cpy.data.V = r, s, v
return cpy, nil
cpy := tx.inner.copy()
cpy.setSignatureValues(signer.ChainID(), v, r, s)
return &Transaction{inner: cpy, time: tx.time}, nil
}
// Cost returns amount + gasprice * gaslimit.
// Cost returns gas * gasPrice + value.
func (tx *Transaction) Cost() *big.Int {
total := new(big.Int).Mul(tx.data.Price, new(big.Int).SetUint64(tx.data.GasLimit))
total.Add(total, tx.data.Amount)
total := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas()))
total.Add(total, tx.Value())
return total
}
// Cost returns amount + gasprice * gaslimit.
// TxCost returns gas * gasPrice + value.
func (tx *Transaction) TxCost(number *big.Int) *big.Int {
total := new(big.Int).Mul(common.GetGasPrice(number), new(big.Int).SetUint64(tx.data.GasLimit))
total.Add(total, tx.data.Amount)
total := new(big.Int).Mul(common.GetGasPrice(number), new(big.Int).SetUint64(tx.Gas()))
total.Add(total, tx.Value())
return total
}
func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
return tx.data.V, tx.data.R, tx.data.S
}
func (tx *Transaction) IsSpecialTransaction() bool {
if tx.To() == nil {
return false
}
toBytes := tx.To().Bytes()
randomizeSMCBytes := common.HexToAddress(common.RandomizeSMC).Bytes()
blockSignersBytes := common.HexToAddress(common.BlockSigners).Bytes()
return bytes.Equal(toBytes, randomizeSMCBytes) || bytes.Equal(toBytes, blockSignersBytes)
to := tx.To()
return to != nil && (*to == common.RandomizeSMCBinary || *to == common.BlockSignersBinary)
}
func (tx *Transaction) IsTradingTransaction() bool {
if tx.To() == nil {
return false
}
if tx.To().String() != common.XDCXAddr {
return false
}
return true
to := tx.To()
return to != nil && *to == common.XDCXAddrBinary
}
func (tx *Transaction) IsLendingTransaction() bool {
if tx.To() == nil {
return false
}
if tx.To().String() != common.XDCXLendingAddress {
return false
}
return true
to := tx.To()
return to != nil && *to == common.XDCXLendingAddressBinary
}
func (tx *Transaction) IsLendingFinalizedTradeTransaction() bool {
if tx.To() == nil {
return false
}
if tx.To().String() != common.XDCXLendingFinalizedTradeAddress {
return false
}
return true
to := tx.To()
return to != nil && *to == common.XDCXLendingFinalizedTradeAddressBinary
}
func (tx *Transaction) IsSkipNonceTransaction() bool {
if tx.To() == nil {
return false
}
if skip := skipNonceDestinationAddress[tx.To().String()]; skip {
return true
}
return false
to := tx.To()
return to != nil && skipNonceDestinationAddress[*to]
}
func (tx *Transaction) IsSigningTransaction() bool {
if tx.To() == nil {
to := tx.To()
if to == nil || *to != common.BlockSignersBinary {
return false
}
if tx.To().String() != common.BlockSigners {
data := tx.Data()
if len(data) != (32*2 + 4) {
return false
}
method := common.ToHex(tx.Data()[0:4])
if method != common.SignMethod {
return false
}
if len(tx.Data()) != (32*2 + 4) {
return false
}
return true
method := common.ToHex(data[0:4])
return method == common.SignMethod
}
func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) {
if tx.To() == nil {
to := tx.To()
if to == nil || *to != common.MasternodeVotingSMCBinary {
return false, nil
}
b := (tx.To().String() == common.MasternodeVotingSMC)
if !b {
return b, nil
var end int
data := tx.Data()
method := common.ToHex(data[0:4])
if method == common.VoteMethod || method == common.ProposeMethod || method == common.ResignMethod {
end = len(data)
} else if method == common.UnvoteMethod {
end = len(data) - 32
} else {
return false, nil
}
method := common.ToHex(tx.Data()[0:4])
if b = (method == common.VoteMethod); b {
addr := tx.Data()[len(tx.Data())-20:]
m := common.BytesToAddress(addr)
return b, &m
}
addr := data[end-20 : end]
m := common.BytesToAddress(addr)
return true, &m
if b = (method == common.UnvoteMethod); b {
addr := tx.Data()[len(tx.Data())-32-20 : len(tx.Data())-32]
m := common.BytesToAddress(addr)
return b, &m
}
if b = (method == common.ProposeMethod); b {
addr := tx.Data()[len(tx.Data())-20:]
m := common.BytesToAddress(addr)
return b, &m
}
if b = (method == common.ResignMethod); b {
addr := tx.Data()[len(tx.Data())-20:]
m := common.BytesToAddress(addr)
return b, &m
}
return b, nil
}
func (tx *Transaction) IsXDCXApplyTransaction() bool {
if tx.To() == nil {
to := tx.To()
if to == nil {
return false
}
@ -426,26 +474,22 @@ func (tx *Transaction) IsXDCXApplyTransaction() bool {
if common.IsTestnet {
addr = common.XDCXListingSMCTestNet
}
if tx.To().String() != addr.String() {
if *to != addr {
return false
}
method := common.ToHex(tx.Data()[0:4])
if method != common.XDCXApplyMethod {
return false
}
data := tx.Data()
// 4 bytes for function name
// 32 bytes for 1 parameter
if len(tx.Data()) != (32 + 4) {
if len(data) != (32 + 4) {
return false
}
return true
method := common.ToHex(data[0:4])
return method == common.XDCXApplyMethod
}
func (tx *Transaction) IsXDCZApplyTransaction() bool {
if tx.To() == nil {
to := tx.To()
if to == nil {
return false
}
@ -453,45 +497,39 @@ func (tx *Transaction) IsXDCZApplyTransaction() bool {
if common.IsTestnet {
addr = common.TRC21IssuerSMCTestNet
}
if tx.To().String() != addr.String() {
if *to != addr {
return false
}
method := common.ToHex(tx.Data()[0:4])
if method != common.XDCZApplyMethod {
return false
}
data := tx.Data()
// 4 bytes for function name
// 32 bytes for 1 parameter
if len(tx.Data()) != (32 + 4) {
if len(data) != (32 + 4) {
return false
}
return true
method := common.ToHex(data[0:4])
return method == common.XDCZApplyMethod
}
func (tx *Transaction) String() string {
var from, to string
if tx.data.V != nil {
// make a best guess about the signer and use that to derive
// the sender.
signer := deriveSigner(tx.data.V)
if f, err := Sender(signer, tx); err != nil { // derive but don't cache
from = "[invalid sender: invalid sig]"
} else {
from = fmt.Sprintf("%x", f[:])
}
sender := tx.From()
if sender != nil {
from = fmt.Sprintf("%x", sender[:])
} else {
from = "[invalid sender: nil V field]"
from = "[invalid sender]"
}
if tx.data.Recipient == nil {
receiver := tx.To()
if receiver == nil {
to = "[contract creation]"
} else {
to = fmt.Sprintf("%x", tx.data.Recipient[:])
to = fmt.Sprintf("%x", receiver[:])
}
enc, _ := rlp.EncodeToBytes(&tx.data)
enc, _ := rlp.EncodeToBytes(tx.Data())
v, r, s := tx.RawSignatureValues()
return fmt.Sprintf(`
TX(%x)
Contract: %v
@ -508,17 +546,17 @@ func (tx *Transaction) String() string {
Hex: %x
`,
tx.Hash(),
tx.data.Recipient == nil,
receiver == nil,
from,
to,
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Amount,
tx.data.Payload,
tx.data.V,
tx.data.R,
tx.data.S,
tx.Nonce(),
tx.GasPrice(),
tx.Gas(),
tx.Value(),
tx.Data(),
v,
r,
s,
enc,
)
}
@ -562,40 +600,47 @@ func TxDifference(a, b Transactions) (keep Transactions) {
type TxByNonce Transactions
func (s TxByNonce) Len() int { return len(s) }
func (s TxByNonce) Less(i, j int) bool { return s[i].data.AccountNonce < s[j].data.AccountNonce }
func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() }
func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// TxByPrice implements both the sort and the heap interface, making it useful
// TxByPriceAndTime implements both the sort and the heap interface, making it useful
// for all at once sorting as well as individually adding and removing elements.
type TxByPrice struct {
type TxByPriceAndTime struct {
txs Transactions
payersSwap map[common.Address]*big.Int
}
func (s TxByPrice) Len() int { return len(s.txs) }
func (s TxByPrice) Less(i, j int) bool {
i_price := s.txs[i].data.Price
func (s TxByPriceAndTime) Len() int { return len(s.txs) }
func (s TxByPriceAndTime) Less(i, j int) bool {
i_price := s.txs[i].GasPrice()
if s.txs[i].To() != nil {
if _, ok := s.payersSwap[*s.txs[i].To()]; ok {
i_price = common.TRC21GasPrice
}
}
j_price := s.txs[j].data.Price
j_price := s.txs[j].GasPrice()
if s.txs[j].To() != nil {
if _, ok := s.payersSwap[*s.txs[j].To()]; ok {
j_price = common.TRC21GasPrice
}
}
return i_price.Cmp(j_price) > 0
}
func (s TxByPrice) Swap(i, j int) { s.txs[i], s.txs[j] = s.txs[j], s.txs[i] }
func (s *TxByPrice) Push(x interface{}) {
// If the prices are equal, use the time the transaction was first seen for
// deterministic sorting
cmp := i_price.Cmp(j_price)
if cmp == 0 {
return s.txs[i].time.Before(s.txs[j].time)
}
return cmp > 0
}
func (s TxByPriceAndTime) Swap(i, j int) { s.txs[i], s.txs[j] = s.txs[j], s.txs[i] }
func (s *TxByPriceAndTime) Push(x interface{}) {
s.txs = append(s.txs, x.(*Transaction))
}
func (s *TxByPrice) Pop() interface{} {
func (s *TxByPriceAndTime) Pop() interface{} {
old := s.txs
n := len(old)
x := old[n-1]
@ -608,7 +653,7 @@ func (s *TxByPrice) Pop() interface{} {
// entire batches of transactions for non-executable accounts.
type TransactionsByPriceAndNonce struct {
txs map[common.Address]Transactions // Per account nonce-sorted list of transactions
heads TxByPrice // Next transaction for each unique account (price heap)
heads TxByPriceAndTime // Next transaction for each unique account (price heap)
signer Signer // Signer for the set of transactions
}
@ -617,11 +662,11 @@ type TransactionsByPriceAndNonce struct {
//
// Note, the input map is reowned so the caller should not interact any more with
// if after providing it to the constructor.
//
// It also classifies special txs and normal txs
func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, signers map[common.Address]struct{}, payersSwap map[common.Address]*big.Int) (*TransactionsByPriceAndNonce, Transactions) {
// Initialize a price based heap with the head transactions
heads := TxByPrice{}
// Initialize a price and received time based heap with the head transactions
heads := TxByPriceAndTime{}
heads.payersSwap = payersSwap
specialTxs := Transactions{}
for _, accTxs := range txs {
@ -698,11 +743,12 @@ type Message struct {
gasLimit uint64
gasPrice *big.Int
data []byte
accessList AccessList
checkNonce bool
balanceTokenFee *big.Int
}
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool, balanceTokenFee *big.Int, number *big.Int) Message {
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, accessList AccessList, checkNonce bool, balanceTokenFee *big.Int, number *big.Int) Message {
if balanceTokenFee != nil {
gasPrice = common.GetGasPrice(number)
}
@ -714,6 +760,7 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
gasLimit: gasLimit,
gasPrice: gasPrice,
data: data,
accessList: accessList,
checkNonce: checkNonce,
balanceTokenFee: balanceTokenFee,
}
@ -728,5 +775,6 @@ func (m Message) Gas() uint64 { return m.gasLimit }
func (m Message) Nonce() uint64 { return m.nonce }
func (m Message) Data() []byte { return m.data }
func (m Message) CheckNonce() bool { return m.checkNonce }
func (m Message) AccessList() AccessList { return m.accessList }
func (m *Message) SetNonce(nonce uint64) { m.nonce = nonce }

View file

@ -0,0 +1,187 @@
package types
import (
"encoding/json"
"errors"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
)
// txJSON is the JSON representation of transactions.
type txJSON struct {
Type hexutil.Uint64 `json:"type"`
// Common transaction fields:
Nonce *hexutil.Uint64 `json:"nonce"`
GasPrice *hexutil.Big `json:"gasPrice"`
Gas *hexutil.Uint64 `json:"gas"`
Value *hexutil.Big `json:"value"`
Data *hexutil.Bytes `json:"input"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
To *common.Address `json:"to"`
// Access list transaction fields:
ChainID *hexutil.Big `json:"chainId,omitempty"`
AccessList *AccessList `json:"accessList,omitempty"`
// Only used for encoding:
Hash common.Hash `json:"hash"`
}
// MarshalJSON marshals as JSON with a hash.
func (t *Transaction) MarshalJSON() ([]byte, error) {
var enc txJSON
// These are set for all tx types.
enc.Hash = t.Hash()
enc.Type = hexutil.Uint64(t.Type())
// Other fields are set conditionally depending on tx type.
switch tx := t.inner.(type) {
case *LegacyTx:
enc.Nonce = (*hexutil.Uint64)(&tx.Nonce)
enc.Gas = (*hexutil.Uint64)(&tx.Gas)
enc.GasPrice = (*hexutil.Big)(tx.GasPrice)
enc.Value = (*hexutil.Big)(tx.Value)
enc.Data = (*hexutil.Bytes)(&tx.Data)
enc.To = t.To()
enc.V = (*hexutil.Big)(tx.V)
enc.R = (*hexutil.Big)(tx.R)
enc.S = (*hexutil.Big)(tx.S)
case *AccessListTx:
enc.ChainID = (*hexutil.Big)(tx.ChainID)
enc.AccessList = &tx.AccessList
enc.Nonce = (*hexutil.Uint64)(&tx.Nonce)
enc.Gas = (*hexutil.Uint64)(&tx.Gas)
enc.GasPrice = (*hexutil.Big)(tx.GasPrice)
enc.Value = (*hexutil.Big)(tx.Value)
enc.Data = (*hexutil.Bytes)(&tx.Data)
enc.To = t.To()
enc.V = (*hexutil.Big)(tx.V)
enc.R = (*hexutil.Big)(tx.R)
enc.S = (*hexutil.Big)(tx.S)
}
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (t *Transaction) UnmarshalJSON(input []byte) error {
var dec txJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
// Decode / verify fields according to transaction type.
var inner TxData
switch dec.Type {
case LegacyTxType:
var itx LegacyTx
inner = &itx
if dec.To != nil {
itx.To = dec.To
}
if dec.Nonce == nil {
return errors.New("missing required field 'nonce' in transaction")
}
itx.Nonce = uint64(*dec.Nonce)
if dec.GasPrice == nil {
return errors.New("missing required field 'gasPrice' in transaction")
}
itx.GasPrice = (*big.Int)(dec.GasPrice)
if dec.Gas == nil {
return errors.New("missing required field 'gas' in transaction")
}
itx.Gas = uint64(*dec.Gas)
if dec.Value == nil {
return errors.New("missing required field 'value' in transaction")
}
itx.Value = (*big.Int)(dec.Value)
if dec.Data == nil {
return errors.New("missing required field 'input' in transaction")
}
itx.Data = *dec.Data
if dec.V == nil {
return errors.New("missing required field 'v' in transaction")
}
itx.V = (*big.Int)(dec.V)
if dec.R == nil {
return errors.New("missing required field 'r' in transaction")
}
itx.R = (*big.Int)(dec.R)
if dec.S == nil {
return errors.New("missing required field 's' in transaction")
}
itx.S = (*big.Int)(dec.S)
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
if withSignature {
if err := sanityCheckSignature(itx.V, itx.R, itx.S, true); err != nil {
return err
}
}
case AccessListTxType:
var itx AccessListTx
inner = &itx
// Access list is optional for now.
if dec.AccessList != nil {
itx.AccessList = *dec.AccessList
}
if dec.ChainID == nil {
return errors.New("missing required field 'chainId' in transaction")
}
itx.ChainID = (*big.Int)(dec.ChainID)
if dec.To != nil {
itx.To = dec.To
}
if dec.Nonce == nil {
return errors.New("missing required field 'nonce' in transaction")
}
itx.Nonce = uint64(*dec.Nonce)
if dec.GasPrice == nil {
return errors.New("missing required field 'gasPrice' in transaction")
}
itx.GasPrice = (*big.Int)(dec.GasPrice)
if dec.Gas == nil {
return errors.New("missing required field 'gas' in transaction")
}
itx.Gas = uint64(*dec.Gas)
if dec.Value == nil {
return errors.New("missing required field 'value' in transaction")
}
itx.Value = (*big.Int)(dec.Value)
if dec.Data == nil {
return errors.New("missing required field 'input' in transaction")
}
itx.Data = *dec.Data
if dec.V == nil {
return errors.New("missing required field 'v' in transaction")
}
itx.V = (*big.Int)(dec.V)
if dec.R == nil {
return errors.New("missing required field 'r' in transaction")
}
itx.R = (*big.Int)(dec.R)
if dec.S == nil {
return errors.New("missing required field 's' in transaction")
}
itx.S = (*big.Int)(dec.S)
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
if withSignature {
if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil {
return err
}
}
default:
return ErrTxTypeNotSupported
}
// Now set the inner transaction.
t.setDecoded(inner, 0)
// TODO: check hash here?
return nil
}

View file

@ -27,9 +27,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/params"
)
var (
ErrInvalidChainId = errors.New("invalid chain id for signer")
)
var ErrInvalidChainId = errors.New("invalid chain id for signer")
var ErrInvalidNilTx = errors.New("invalid nil tx")
// sigCache is used to cache the derived sender and contains
// the signer used to derive it.
@ -42,6 +41,8 @@ type sigCache struct {
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsEIP1559(blockNumber):
signer = NewEIP2930Signer(config.ChainId)
case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId)
case config.IsHomestead(blockNumber):
@ -52,7 +53,40 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
return signer
}
// SignTx signs the transaction using the given signer and private key
// LatestSigner returns the 'most permissive' Signer available for the given chain
// configuration. Specifically, this enables support of EIP-155 replay protection and
// EIP-2930 access list transactions when their respective forks are scheduled to occur at
// any block number in the chain config.
//
// Use this in transaction-handling code where the current block number is unknown. If you
// have the current block number available, use MakeSigner instead.
func LatestSigner(config *params.ChainConfig) Signer {
if config.ChainId != nil {
if common.Eip1559Block.Uint64() != 9999999999 || config.Eip1559Block != nil {
return NewEIP2930Signer(config.ChainId)
}
if config.EIP155Block != nil {
return NewEIP155Signer(config.ChainId)
}
}
return HomesteadSigner{}
}
// LatestSignerForChainID returns the 'most permissive' Signer available. Specifically,
// this enables support for EIP-155 replay protection and all implemented EIP-2718
// transaction types if chainID is non-nil.
//
// Use this in transaction-handling code where the current block number and fork
// configuration are unknown. If you have a ChainConfig, use LatestSigner instead.
// If you have a ChainConfig and know the current block number, use MakeSigner instead.
func LatestSignerForChainID(chainID *big.Int) Signer {
if chainID == nil {
return HomesteadSigner{}
}
return NewEIP2930Signer(chainID)
}
// SignTx signs the transaction using the given signer and private key.
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], prv)
@ -62,6 +96,27 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err
return tx.WithSignature(s, sig)
}
// SignNewTx creates a transaction and signs it.
func SignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) (*Transaction, error) {
tx := NewTx(txdata)
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], prv)
if err != nil {
return nil, err
}
return tx.WithSignature(s, sig)
}
// MustSignNewTx creates a transaction and signs it.
// This panics if the transaction cannot be signed.
func MustSignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) *Transaction {
tx, err := SignNewTx(prv, s, txdata)
if err != nil {
panic(err)
}
return tx
}
// Sender returns the address derived from the signature (V, R, S) using secp256k1
// elliptic curve and an error if it failed deriving or upon an incorrect
// signature.
@ -70,6 +125,10 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err
// signing method. The cache is invalidated if the cached signer does
// not match the signer used in the current call.
func Sender(signer Signer, tx *Transaction) (common.Address, error) {
if tx == nil {
return common.Address{}, ErrInvalidNilTx
}
if sc := tx.from.Load(); sc != nil {
sigCache := sc.(sigCache)
// If the signer used to derive from in a previous
@ -88,21 +147,112 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
return addr, nil
}
// Signer encapsulates transaction signature handling. Note that this interface is not a
// stable API and may change at any time to accommodate new protocol rules.
// Signer encapsulates transaction signature handling. The name of this type is slightly
// misleading because Signers don't actually sign, they're just for validating and
// processing of signatures.
//
// Note that this interface is not a stable API and may change at any time to accommodate
// new protocol rules.
type Signer interface {
// Sender returns the sender address of the transaction.
Sender(tx *Transaction) (common.Address, error)
// SignatureValues returns the raw R, S, V values corresponding to the
// given signature.
SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
// Hash returns the hash to be signed.
ChainID() *big.Int
// Hash returns 'signature hash', i.e. the transaction hash that is signed by the
// private key. This hash does not uniquely identify the transaction.
Hash(tx *Transaction) common.Hash
// Equal returns true if the given signer is the same as the receiver.
Equal(Signer) bool
}
// EIP155Transaction implements Signer using the EIP155 rules.
type eip2930Signer struct{ EIP155Signer }
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
// EIP-155 replay protected transactions, and legacy Homestead transactions.
func NewEIP2930Signer(chainId *big.Int) Signer {
return eip2930Signer{NewEIP155Signer(chainId)}
}
func (s eip2930Signer) ChainID() *big.Int {
return s.chainId
}
func (s eip2930Signer) Equal(s2 Signer) bool {
x, ok := s2.(eip2930Signer)
return ok && x.chainId.Cmp(s.chainId) == 0
}
func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
V, R, S := tx.RawSignatureValues()
switch tx.Type() {
case LegacyTxType:
return s.EIP155Signer.Sender(tx)
case AccessListTxType:
// ACL txs are defined to use 0 and 1 as their recovery id, add
// 27 to become equivalent to unprotected Homestead signatures.
V = new(big.Int).Add(V, big.NewInt(27))
default:
return common.Address{}, ErrTxTypeNotSupported
}
if tx.ChainId().Cmp(s.chainId) != 0 {
return common.Address{}, ErrInvalidChainId
}
return recoverPlain(s.Hash(tx), R, S, V, true)
}
func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
switch txdata := tx.inner.(type) {
case *LegacyTx:
return s.EIP155Signer.SignatureValues(tx, sig)
case *AccessListTx:
// Check that chain ID of tx matches the signer. We also accept ID zero here,
// because it indicates that the chain ID was not specified in the tx.
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
return nil, nil, nil, ErrInvalidChainId
}
R, S, _ = decodeSignature(sig)
V = big.NewInt(int64(sig[64]))
default:
return nil, nil, nil, ErrTxTypeNotSupported
}
return R, S, V, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s eip2930Signer) Hash(tx *Transaction) common.Hash {
switch tx.Type() {
case LegacyTxType:
return s.EIP155Signer.Hash(tx)
case AccessListTxType:
return prefixedRlpHash(
tx.Type(),
[]interface{}{
s.chainId,
tx.Nonce(),
tx.GasPrice(),
tx.Gas(),
tx.To(),
tx.Value(),
tx.Data(),
tx.AccessList(),
})
default:
// This _should_ not happen, but in case someone sends in a bad
// json struct via RPC, it's probably more prudent to return an
// empty hash instead of killing the node with a panic
//panic("Unsupported transaction type: %d", tx.typ)
return common.Hash{}
}
}
// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
// are replay-protected as well as unprotected homestead transactions.
type EIP155Signer struct {
chainId, chainIdMul *big.Int
}
@ -117,6 +267,10 @@ func NewEIP155Signer(chainId *big.Int) EIP155Signer {
}
}
func (s EIP155Signer) ChainID() *big.Int {
return s.chainId
}
func (s EIP155Signer) Equal(s2 Signer) bool {
eip155, ok := s2.(EIP155Signer)
return ok && eip155.chainId.Cmp(s.chainId) == 0
@ -125,24 +279,28 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
var big8 = big.NewInt(8)
func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
if tx.Type() != LegacyTxType {
return common.Address{}, ErrTxTypeNotSupported
}
if !tx.Protected() {
return HomesteadSigner{}.Sender(tx)
}
if tx.ChainId().Cmp(s.chainId) != 0 {
return common.Address{}, ErrInvalidChainId
}
V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
V, R, S := tx.RawSignatureValues()
V = new(big.Int).Sub(V, s.chainIdMul)
V.Sub(V, big8)
return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
return recoverPlain(s.Hash(tx), R, S, V, true)
}
// WithSignature returns a new transaction with the given signature. This signature
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
if err != nil {
return nil, nil, nil, err
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
R, S, V = decodeSignature(sig)
if s.chainId.Sign() != 0 {
V = big.NewInt(int64(sig[64] + 35))
V.Add(V, s.chainIdMul)
@ -154,12 +312,12 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
// It does not uniquely identify the transaction.
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Recipient,
tx.data.Amount,
tx.data.Payload,
tx.Nonce(),
tx.GasPrice(),
tx.Gas(),
tx.To(),
tx.Value(),
tx.Data(),
s.chainId, uint(0), uint(0),
})
}
@ -168,6 +326,10 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
// homestead rules.
type HomesteadSigner struct{ FrontierSigner }
func (s HomesteadSigner) ChainID() *big.Int {
return nil
}
func (s HomesteadSigner) Equal(s2 Signer) bool {
_, ok := s2.(HomesteadSigner)
return ok
@ -180,25 +342,39 @@ func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v
}
func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
if tx.Type() != LegacyTxType {
return common.Address{}, ErrTxTypeNotSupported
}
v, r, s := tx.RawSignatureValues()
return recoverPlain(hs.Hash(tx), r, s, v, true)
}
type FrontierSigner struct{}
func (s FrontierSigner) ChainID() *big.Int {
return nil
}
func (s FrontierSigner) Equal(s2 Signer) bool {
_, ok := s2.(FrontierSigner)
return ok
}
func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
if tx.Type() != LegacyTxType {
return common.Address{}, ErrTxTypeNotSupported
}
v, r, s := tx.RawSignatureValues()
return recoverPlain(fs.Hash(tx), r, s, v, false)
}
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
if tx.Type() != LegacyTxType {
return nil, nil, nil, ErrTxTypeNotSupported
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
r, s, v = decodeSignature(sig)
return r, s, v, nil
}
@ -206,17 +382,23 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
// It does not uniquely identify the transaction.
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
tx.data.AccountNonce,
tx.data.Price,
tx.data.GasLimit,
tx.data.Recipient,
tx.data.Amount,
tx.data.Payload,
tx.Nonce(),
tx.GasPrice(),
tx.Gas(),
tx.To(),
tx.Value(),
tx.Data(),
})
}
func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
func decodeSignature(sig []byte) (r, s, v *big.Int) {
if len(sig) != crypto.SignatureLength {
panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
}
r = new(big.Int).SetBytes(sig[:32])
s = new(big.Int).SetBytes(sig[32:64])
v = new(big.Int).SetBytes([]byte{sig[64] + 27})
return r, s, v
}
func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {

View file

@ -20,8 +20,12 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"math/big"
"reflect"
"testing"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/crypto"
@ -31,6 +35,8 @@ import (
// The values in those tests are from the Transaction Tests
// at github.com/ethereum/tests.
var (
testAddr = common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b")
emptyTx = NewTransaction(
0,
common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
@ -40,7 +46,7 @@ var (
rightvrsTx, _ = NewTransaction(
3,
common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
testAddr,
big.NewInt(10),
2000,
big.NewInt(1),
@ -49,8 +55,32 @@ var (
HomesteadSigner{},
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a301"),
)
emptyEip2718Tx = NewTx(&AccessListTx{
ChainID: big.NewInt(1),
Nonce: 3,
To: &testAddr,
Value: big.NewInt(10),
Gas: 25000,
GasPrice: big.NewInt(1),
Data: common.FromHex("5544"),
})
signedEip2718Tx, _ = emptyEip2718Tx.WithSignature(
NewEIP2930Signer(big.NewInt(1)),
common.Hex2Bytes("c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b266032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d3752101"),
)
)
func TestDecodeEmptyTypedTx(t *testing.T) {
input := []byte{0x80}
var tx Transaction
err := rlp.DecodeBytes(input, &tx)
if err != errEmptyTypedTx {
t.Fatal("wrong error:", err)
}
}
func TestTransactionSigHash(t *testing.T) {
var homestead HomesteadSigner
if homestead.Hash(emptyTx) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
@ -72,6 +102,117 @@ func TestTransactionEncode(t *testing.T) {
}
}
func TestEIP2718TransactionSigHash(t *testing.T) {
s := NewEIP2930Signer(big.NewInt(1))
if s.Hash(emptyEip2718Tx) != common.HexToHash("49b486f0ec0a60dfbbca2d30cb07c9e8ffb2a2ff41f29a1ab6737475f6ff69f3") {
t.Errorf("empty EIP-2718 transaction hash mismatch, got %x", s.Hash(emptyEip2718Tx))
}
if s.Hash(signedEip2718Tx) != common.HexToHash("49b486f0ec0a60dfbbca2d30cb07c9e8ffb2a2ff41f29a1ab6737475f6ff69f3") {
t.Errorf("signed EIP-2718 transaction hash mismatch, got %x", s.Hash(signedEip2718Tx))
}
}
// This test checks signature operations on access list transactions.
func TestEIP2930Signer(t *testing.T) {
var (
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
keyAddr = crypto.PubkeyToAddress(key.PublicKey)
signer1 = NewEIP2930Signer(big.NewInt(1))
signer2 = NewEIP2930Signer(big.NewInt(2))
tx0 = NewTx(&AccessListTx{Nonce: 1})
tx1 = NewTx(&AccessListTx{ChainID: big.NewInt(1), Nonce: 1})
tx2, _ = SignNewTx(key, signer2, &AccessListTx{ChainID: big.NewInt(2), Nonce: 1})
)
tests := []struct {
tx *Transaction
signer Signer
wantSignerHash common.Hash
wantSenderErr error
wantSignErr error
wantHash common.Hash // after signing
}{
{
tx: tx0,
signer: signer1,
wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
wantSenderErr: ErrInvalidChainId,
wantHash: common.HexToHash("1ccd12d8bbdb96ea391af49a35ab641e219b2dd638dea375f2bc94dd290f2549"),
},
{
tx: tx1,
signer: signer1,
wantSenderErr: ErrInvalidSig,
wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
wantHash: common.HexToHash("1ccd12d8bbdb96ea391af49a35ab641e219b2dd638dea375f2bc94dd290f2549"),
},
{
// This checks what happens when trying to sign an unsigned tx for the wrong chain.
tx: tx1,
signer: signer2,
wantSenderErr: ErrInvalidChainId,
wantSignerHash: common.HexToHash("367967247499343401261d718ed5aa4c9486583e4d89251afce47f4a33c33362"),
wantSignErr: ErrInvalidChainId,
},
{
// This checks what happens when trying to re-sign a signed tx for the wrong chain.
tx: tx2,
signer: signer1,
wantSenderErr: ErrInvalidChainId,
wantSignerHash: common.HexToHash("846ad7672f2a3a40c1f959cd4a8ad21786d620077084d84c8d7c077714caa139"),
wantSignErr: ErrInvalidChainId,
},
}
for i, test := range tests {
sigHash := test.signer.Hash(test.tx)
if sigHash != test.wantSignerHash {
t.Errorf("test %d: wrong sig hash: got %x, want %x", i, sigHash, test.wantSignerHash)
}
sender, err := Sender(test.signer, test.tx)
if !errors.Is(err, test.wantSenderErr) {
t.Errorf("test %d: wrong Sender error %q", i, err)
}
if err == nil && sender != keyAddr {
t.Errorf("test %d: wrong sender address %x", i, sender)
}
signedTx, err := SignTx(test.tx, test.signer, key)
if !errors.Is(err, test.wantSignErr) {
t.Fatalf("test %d: wrong SignTx error %q", i, err)
}
if signedTx != nil {
if signedTx.Hash() != test.wantHash {
t.Errorf("test %d: wrong tx hash after signing: got %x, want %x", i, signedTx.Hash(), test.wantHash)
}
}
}
}
func TestEIP2718TransactionEncode(t *testing.T) {
// RLP representation
{
have, err := rlp.EncodeToBytes(signedEip2718Tx)
if err != nil {
t.Fatalf("encode error: %v", err)
}
want := common.FromHex("b86601f8630103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a825544c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521")
if !bytes.Equal(have, want) {
t.Errorf("encoded RLP mismatch, got %x", have)
}
}
// Binary representation
{
have, err := signedEip2718Tx.MarshalBinary()
if err != nil {
t.Fatalf("encode error: %v", err)
}
want := common.FromHex("01f8630103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a825544c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521")
if !bytes.Equal(have, want) {
t.Errorf("encoded RLP mismatch, got %x", have)
}
}
}
func decodeTx(data []byte) (*Transaction, error) {
var tx Transaction
t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx)
@ -233,3 +374,174 @@ func TestTransactionJSON(t *testing.T) {
}
}
}
// Tests that if multiple transactions have the same price, the ones seen earlier
// are prioritized to avoid network spam attacks aiming for a specific ordering.
func TestTransactionTimeSort(t *testing.T) {
// Generate a batch of accounts to start with
keys := make([]*ecdsa.PrivateKey, 5)
for i := 0; i < len(keys); i++ {
keys[i], _ = crypto.GenerateKey()
}
signer := HomesteadSigner{}
// Generate a batch of transactions with overlapping prices, but different creation times
groups := map[common.Address]Transactions{}
for start, key := range keys {
addr := crypto.PubkeyToAddress(key.PublicKey)
tx, _ := SignTx(NewTransaction(0, common.Address{}, big.NewInt(100), 100, big.NewInt(1), nil), signer, key)
tx.time = time.Unix(0, int64(len(keys)-start))
groups[addr] = append(groups[addr], tx)
}
// Sort the transactions and cross check the nonce ordering
txset, _ := NewTransactionsByPriceAndNonce(signer, groups, nil, map[common.Address]*big.Int{})
txs := Transactions{}
for tx := txset.Peek(); tx != nil; tx = txset.Peek() {
txs = append(txs, tx)
txset.Shift()
}
if len(txs) != len(keys) {
t.Errorf("expected %d transactions, found %d", len(keys), len(txs))
}
for i, txi := range txs {
fromi, _ := Sender(signer, txi)
if i+1 < len(txs) {
next := txs[i+1]
fromNext, _ := Sender(signer, next)
if txi.GasPrice().Cmp(next.GasPrice()) < 0 {
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", i, fromi[:4], txi.GasPrice(), i+1, fromNext[:4], next.GasPrice())
}
// Make sure time order is ascending if the txs have the same gas price
if txi.GasPrice().Cmp(next.GasPrice()) == 0 && txi.time.After(next.time) {
t.Errorf("invalid received time ordering: tx #%d (A=%x T=%v) > tx #%d (A=%x T=%v)", i, fromi[:4], txi.time, i+1, fromNext[:4], next.time)
}
}
}
}
// TestTransactionCoding tests serializing/de-serializing to/from rlp and JSON.
func TestTransactionCoding(t *testing.T) {
key, err := crypto.GenerateKey()
if err != nil {
t.Fatalf("could not generate key: %v", err)
}
var (
signer = NewEIP2930Signer(common.Big1)
addr = common.HexToAddress("0x0000000000000000000000000000000000000001")
recipient = common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87")
accesses = AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}}
)
for i := uint64(0); i < 500; i++ {
var txdata TxData
switch i % 5 {
case 0:
// Legacy tx.
txdata = &LegacyTx{
Nonce: i,
To: &recipient,
Gas: 1,
GasPrice: big.NewInt(2),
Data: []byte("abcdef"),
}
case 1:
// Legacy tx contract creation.
txdata = &LegacyTx{
Nonce: i,
Gas: 1,
GasPrice: big.NewInt(2),
Data: []byte("abcdef"),
}
case 2:
// Tx with non-zero access list.
txdata = &AccessListTx{
ChainID: big.NewInt(1),
Nonce: i,
To: &recipient,
Gas: 123457,
GasPrice: big.NewInt(10),
AccessList: accesses,
Data: []byte("abcdef"),
}
case 3:
// Tx with empty access list.
txdata = &AccessListTx{
ChainID: big.NewInt(1),
Nonce: i,
To: &recipient,
Gas: 123457,
GasPrice: big.NewInt(10),
Data: []byte("abcdef"),
}
case 4:
// Contract creation with access list.
txdata = &AccessListTx{
ChainID: big.NewInt(1),
Nonce: i,
Gas: 123457,
GasPrice: big.NewInt(10),
AccessList: accesses,
}
}
tx, err := SignNewTx(key, signer, txdata)
if err != nil {
t.Fatalf("could not sign transaction: %v", err)
}
// RLP
parsedTx, err := encodeDecodeBinary(tx)
if err != nil {
t.Fatal(err)
}
assertEqual(parsedTx, tx)
// JSON
parsedTx, err = encodeDecodeJSON(tx)
if err != nil {
t.Fatal(err)
}
assertEqual(parsedTx, tx)
}
}
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
data, err := json.Marshal(tx)
if err != nil {
return nil, fmt.Errorf("json encoding failed: %v", err)
}
var parsedTx = &Transaction{}
if err := json.Unmarshal(data, &parsedTx); err != nil {
return nil, fmt.Errorf("json decoding failed: %v", err)
}
return parsedTx, nil
}
func encodeDecodeBinary(tx *Transaction) (*Transaction, error) {
data, err := tx.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("rlp encoding failed: %v", err)
}
var parsedTx = &Transaction{}
if err := parsedTx.UnmarshalBinary(data); err != nil {
return nil, fmt.Errorf("rlp decoding failed: %v", err)
}
return parsedTx, nil
}
func assertEqual(orig *Transaction, cpy *Transaction) error {
// compare nonce, price, gaslimit, recipient, amount, payload, V, R, S
if want, got := orig.Hash(), cpy.Hash(); want != got {
return fmt.Errorf("parsed tx differs from original tx, want %v, got %v", want, got)
}
if want, got := orig.ChainId(), cpy.ChainId(); want.Cmp(got) != 0 {
return fmt.Errorf("invalid chain id, want %d, got %d", want, got)
}
if orig.AccessList() != nil {
if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) {
return errors.New("access list wrong!")
}
}
return nil
}

View file

@ -0,0 +1,177 @@
// Copyright 2021 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 vm
import (
"math/big"
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
)
// accessList is an accumulator for the set of accounts and storage slots an EVM
// contract execution touches.
type accessList map[common.Address]accessListSlots
// accessListSlots is an accumulator for the set of storage slots within a single
// contract that an EVM contract execution touches.
type accessListSlots map[common.Hash]struct{}
// newAccessList creates a new accessList.
func newAccessList() accessList {
return make(map[common.Address]accessListSlots)
}
// addAddress adds an address to the accesslist.
func (al accessList) addAddress(address common.Address) {
// Set address if not previously present
if _, present := al[address]; !present {
al[address] = make(map[common.Hash]struct{})
}
}
// addSlot adds a storage slot to the accesslist.
func (al accessList) addSlot(address common.Address, slot common.Hash) {
// Set address if not previously present
al.addAddress(address)
// Set the slot on the surely existent storage set
al[address][slot] = struct{}{}
}
// equal checks if the content of the current access list is the same as the
// content of the other one.
func (al accessList) equal(other accessList) bool {
// Cross reference the accounts first
if len(al) != len(other) {
return false
}
for addr := range al {
if _, ok := other[addr]; !ok {
return false
}
}
for addr := range other {
if _, ok := al[addr]; !ok {
return false
}
}
// Accounts match, cross reference the storage slots too
for addr, slots := range al {
otherslots := other[addr]
if len(slots) != len(otherslots) {
return false
}
for hash := range slots {
if _, ok := otherslots[hash]; !ok {
return false
}
}
for hash := range otherslots {
if _, ok := slots[hash]; !ok {
return false
}
}
}
return true
}
// accesslist converts the accesslist to a types.AccessList.
func (al accessList) accessList() types.AccessList {
acl := make(types.AccessList, 0, len(al))
for addr, slots := range al {
tuple := types.AccessTuple{Address: addr}
for slot := range slots {
tuple.StorageKeys = append(tuple.StorageKeys, slot)
}
acl = append(acl, tuple)
}
return acl
}
// AccessListTracer is a tracer that accumulates touched accounts and storage
// slots into an internal set.
type AccessListTracer struct {
excl map[common.Address]struct{} // Set of account to exclude from the list
list accessList // Set of accounts and storage slots touched
}
// NewAccessListTracer creates a new tracer that can generate AccessLists.
// An optional AccessList can be specified to occupy slots and addresses in
// the resulting accesslist.
func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompiles []common.Address) *AccessListTracer {
excl := map[common.Address]struct{}{
from: {}, to: {},
}
for _, addr := range precompiles {
excl[addr] = struct{}{}
}
list := newAccessList()
for _, al := range acl {
if _, ok := excl[al.Address]; !ok {
list.addAddress(al.Address)
}
for _, slot := range al.StorageKeys {
list.addSlot(al.Address, slot)
}
}
return &AccessListTracer{
excl: excl,
list: list,
}
}
func (a *AccessListTracer) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
}
// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist.
func (a *AccessListTracer) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
stack := scope.Stack
if (op == SLOAD || op == SSTORE) && stack.len() >= 1 {
slot := common.Hash(stack.data[stack.len()-1].Bytes32())
a.list.addSlot(scope.Contract.Address(), slot)
}
if (op == EXTCODECOPY || op == EXTCODEHASH || op == EXTCODESIZE || op == BALANCE || op == SELFDESTRUCT) && stack.len() >= 1 {
addr := common.Address(stack.data[stack.len()-1].Bytes20())
if _, ok := a.excl[addr]; !ok {
a.list.addAddress(addr)
}
}
if (op == DELEGATECALL || op == CALL || op == STATICCALL || op == CALLCODE) && stack.len() >= 5 {
addr := common.Address(stack.data[stack.len()-2].Bytes20())
if _, ok := a.excl[addr]; !ok {
a.list.addAddress(addr)
}
}
}
func (*AccessListTracer) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
}
func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {}
// AccessList returns the current accesslist maintained by the tracer.
func (a *AccessListTracer) AccessList() types.AccessList {
return a.list.accessList()
}
// Equal returns if the content of two access list traces are equal.
func (a *AccessListTracer) Equal(other *AccessListTracer) bool {
return a.list.equal(other.list)
}

View file

@ -120,6 +120,20 @@ func init() {
}
}
// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsXDCxDisable:
return PrecompiledAddressesXDCv2
case rules.IsIstanbul:
return PrecompiledAddressesIstanbul
case rules.IsByzantium:
return PrecompiledAddressesByzantium
default:
return PrecompiledAddressesHomestead
}
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
gas := p.RequiredGas(input)

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