mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
rebase from dev-upgrade
This commit is contained in:
commit
d28c7f659d
213 changed files with 10650 additions and 2919 deletions
13
XDCx/XDCx.go
13
XDCx/XDCx.go
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
|
||||
Config: ¶ms.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 := ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
||||
config := ¶ms.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: ¶ms.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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
220
core/tx_list.go
220
core/tx_list.go
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
470
core/tx_pool.go
470
core/tx_pool.go
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
115
core/types/access_list_tx.go
Normal file
115
core/types/access_list_tx.go
Normal 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
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
43
core/types/gen_access_tuple.go
Normal file
43
core/types/gen_access_tuple.go
Normal 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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
59
core/types/hashing.go
Normal 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
111
core/types/legacy_tx.go
Normal 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
|
||||
}
|
||||
|
|
@ -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"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
170
core/types/receipt_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
187
core/types/transaction_marshalling.go
Normal file
187
core/types/transaction_marshalling.go
Normal 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
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
177
core/vm/access_list_tracer.go
Normal file
177
core/vm/access_list_tracer.go
Normal 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)
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in a new issue