Merge pull request #768 from gzliudan/upgrade_common

upgrade package common
This commit is contained in:
Daniel Liu 2024-12-28 09:08:16 +08:00 committed by GitHub
commit 3a0d5b6212
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
115 changed files with 3099 additions and 1671 deletions

View file

@ -52,8 +52,8 @@ type XDCX struct {
// Order related
db XDCxDAO.XDCXDAO
mongodb XDCxDAO.XDCXDAO
Triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
StateCache tradingstate.Database // State database to reuse between imports (contains state cache) *XDCx_state.TradingStateDB
Triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
StateCache tradingstate.Database // State database to reuse between imports (contains state cache) *XDCx_state.TradingStateDB
orderNonce map[common.Address]*big.Int
@ -94,7 +94,7 @@ func NewMongoDBEngine(cfg *Config) *XDCxDAO.MongoDatabase {
func New(cfg *Config) *XDCX {
XDCX := &XDCX{
orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil),
Triegc: prque.New[int64, common.Hash](nil),
tokenDecimalCache: lru.NewCache[common.Address, *big.Int](defaultCacheLimit),
orderCache: lru.NewCache[common.Hash, map[common.Hash]tradingstate.OrderHistoryItem](tradingstate.OrderCacheLimit),
}
@ -579,7 +579,7 @@ func (XDCx *XDCX) HasTradingState(block *types.Block, author common.Address) boo
return err == nil
}
func (XDCx *XDCX) GetTriegc() *prque.Prque {
func (XDCx *XDCX) GetTriegc() *prque.Prque[int64, common.Hash] {
return XDCx.Triegc
}

View file

@ -525,7 +525,7 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *tradingsta
matchingFee = new(big.Int).Add(matchingFee, common.RelayerFee)
matchingFee = new(big.Int).Add(matchingFee, common.RelayerFee)
if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) {
if takerExOwner.Hash().IsZero() || makerExOwner.Hash().IsZero() {
return fmt.Errorf("empty echange owner: taker: %v , maker : %v", takerExOwner, makerExOwner)
}
mapBalances := map[common.Address]map[common.Address]*big.Int{}

View file

@ -56,7 +56,7 @@ func (t *TradingStateDB) DumpAskTrie(orderBook common.Hash) (map[*big.Int]DumpOr
it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
continue
}
price := new(big.Int).SetBytes(priceHash.Bytes())
@ -99,7 +99,7 @@ func (t *TradingStateDB) DumpBidTrie(orderBook common.Hash) (map[*big.Int]DumpOr
it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
continue
}
price := new(big.Int).SetBytes(priceHash.Bytes())
@ -142,7 +142,7 @@ func (t *TradingStateDB) GetBids(orderBook common.Hash) (map[*big.Int]*big.Int,
it := trie.NewIterator(exhangeObject.getBidsTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
continue
}
price := new(big.Int).SetBytes(priceHash.Bytes())
@ -185,7 +185,7 @@ func (t *TradingStateDB) GetAsks(orderBook common.Hash) (map[*big.Int]*big.Int,
it := trie.NewIterator(exhangeObject.getAsksTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
continue
}
price := new(big.Int).SetBytes(priceHash.Bytes())
@ -224,7 +224,7 @@ func (s *stateOrderList) DumpOrderList(db Database) DumpOrderList {
orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
if keyHash.IsZero() {
continue
}
if _, exist := s.cachedStorage[keyHash]; exist {
@ -235,7 +235,7 @@ func (s *stateOrderList) DumpOrderList(db Database) DumpOrderList {
}
}
for key, value := range s.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
}
}
@ -277,7 +277,7 @@ func (s *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
orderListIt := trie.NewIterator(s.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
if keyHash.IsZero() {
continue
}
if _, exist := s.cachedStorage[keyHash]; exist {
@ -288,7 +288,7 @@ func (s *stateLendingBook) DumpOrderList(db Database) DumpOrderList {
}
}
for key, value := range s.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
}
}
@ -311,7 +311,7 @@ func (l *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, e
it := trie.NewIterator(l.getTrie(db).NodeIterator(nil))
for it.Next() {
lendingBook := common.BytesToHash(it.Key)
if common.EmptyHash(lendingBook) {
if lendingBook.IsZero() {
continue
}
if _, exist := l.stateLendingBooks[lendingBook]; exist {
@ -326,7 +326,7 @@ func (l *liquidationPriceState) DumpLendingBook(db Database) (DumpLendingBook, e
}
}
for lendingBook, stateLendingBook := range l.stateLendingBooks {
if !common.EmptyHash(lendingBook) {
if !lendingBook.IsZero() {
result.LendingBooks[lendingBook] = stateLendingBook.DumpOrderList(db)
}
}
@ -342,7 +342,7 @@ func (t *TradingStateDB) DumpLiquidationPriceTrie(orderBook common.Hash) (map[*b
it := trie.NewIterator(exhangeObject.getLiquidationPriceTrie(t.db).NodeIterator(nil))
for it.Next() {
priceHash := common.BytesToHash(it.Key)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
continue
}
price := new(big.Int).SetBytes(priceHash.Bytes())

View file

@ -118,7 +118,7 @@ func (s *stateLendingBook) getAllTradeIds(db Database) []common.Hash {
return tradeIds
}
for id, value := range s.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
tradeIds = append(tradeIds, id)
}
}

View file

@ -85,16 +85,16 @@ func (te *tradingExchanges) empty() bool {
if te.data.TotalQuantity != nil && te.data.TotalQuantity.Sign() > 0 {
return false
}
if !common.EmptyHash(te.data.AskRoot) {
if !te.data.AskRoot.IsZero() {
return false
}
if !common.EmptyHash(te.data.BidRoot) {
if !te.data.BidRoot.IsZero() {
return false
}
if !common.EmptyHash(te.data.OrderRoot) {
if !te.data.OrderRoot.IsZero() {
return false
}
if !common.EmptyHash(te.data.LiquidationPriceRoot) {
if !te.data.LiquidationPriceRoot.IsZero() {
return false
}
return true

View file

@ -358,7 +358,7 @@ func (t *TradingStateDB) GetBestAskPrice(orderBook common.Hash) (*big.Int, *big.
stateObject := t.getStateExchangeObject(orderBook)
if stateObject != nil {
priceHash := stateObject.getBestPriceAsksTrie(t.db)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
return Zero, Zero
}
orderList := stateObject.getStateOrderListAskObject(t.db, priceHash)
@ -375,7 +375,7 @@ func (t *TradingStateDB) GetBestBidPrice(orderBook common.Hash) (*big.Int, *big.
stateObject := t.getStateExchangeObject(orderBook)
if stateObject != nil {
priceHash := stateObject.getBestBidsTrie(t.db)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
return Zero, Zero
}
orderList := stateObject.getStateBidOrderListObject(t.db, priceHash)

View file

@ -18,11 +18,12 @@ package tradingstate
import (
"fmt"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
"math"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
)
func TestEchangeStates(t *testing.T) {

View file

@ -36,8 +36,8 @@ var (
)
type Lending struct {
Triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
StateCache lendingstate.Database // State database to reuse between imports (contains state cache) *lendingstate.TradingStateDB
Triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
StateCache lendingstate.Database // State database to reuse between imports (contains state cache) *lendingstate.TradingStateDB
orderNonce map[common.Address]*big.Int
@ -61,7 +61,7 @@ func (l *Lending) Stop() error {
func New(XDCx *XDCx.XDCX) *Lending {
lending := &Lending{
orderNonce: make(map[common.Address]*big.Int),
Triegc: prque.New(nil),
Triegc: prque.New[int64, common.Hash](nil),
lendingItemHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingItemHistoryItem](defaultCacheLimit),
lendingTradeHistory: lru.NewCache[common.Hash, map[common.Hash]lendingstate.LendingTradeHistoryItem](defaultCacheLimit),
}
@ -682,7 +682,7 @@ func (l *Lending) HasLendingState(block *types.Block, author common.Address) boo
return err == nil
}
func (l *Lending) GetTriegc() *prque.Prque {
func (l *Lending) GetTriegc() *prque.Prque[int64, common.Hash] {
return l.Triegc
}

View file

@ -48,7 +48,7 @@ func (ls *LendingStateDB) DumpInvestingTrie(orderBook common.Hash) (map[*big.Int
it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
if interestHash.IsZero() {
continue
}
interest := new(big.Int).SetBytes(interestHash.Bytes())
@ -91,7 +91,7 @@ func (ls *LendingStateDB) DumpBorrowingTrie(orderBook common.Hash) (map[*big.Int
it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
if interestHash.IsZero() {
continue
}
interest := new(big.Int).SetBytes(interestHash.Bytes())
@ -134,7 +134,7 @@ func (ls *LendingStateDB) GetInvestings(orderBook common.Hash) (map[*big.Int]*bi
it := trie.NewIterator(exhangeObject.getInvestingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
if interestHash.IsZero() {
continue
}
interest := new(big.Int).SetBytes(interestHash.Bytes())
@ -177,7 +177,7 @@ func (ls *LendingStateDB) GetBorrowings(orderBook common.Hash) (map[*big.Int]*bi
it := trie.NewIterator(exhangeObject.getBorrowingTrie(ls.db).NodeIterator(nil))
for it.Next() {
interestHash := common.BytesToHash(it.Key)
if common.EmptyHash(interestHash) {
if interestHash.IsZero() {
continue
}
interest := new(big.Int).SetBytes(interestHash.Bytes())
@ -216,7 +216,7 @@ func (il *itemListState) DumpItemList(db Database) DumpOrderList {
orderListIt := trie.NewIterator(il.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
if keyHash.IsZero() {
continue
}
if _, exist := il.cachedStorage[keyHash]; exist {
@ -227,7 +227,7 @@ func (il *itemListState) DumpItemList(db Database) DumpOrderList {
}
}
for key, value := range il.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
}
}
@ -265,7 +265,7 @@ func (lts *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
orderListIt := trie.NewIterator(lts.getTrie(db).NodeIterator(nil))
for orderListIt.Next() {
keyHash := common.BytesToHash(orderListIt.Key)
if common.EmptyHash(keyHash) {
if keyHash.IsZero() {
continue
}
if _, exist := lts.cachedStorage[keyHash]; exist {
@ -276,7 +276,7 @@ func (lts *liquidationTimeState) DumpItemList(db Database) DumpOrderList {
}
}
for key, value := range lts.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
mapResult.Orders[new(big.Int).SetBytes(key.Bytes())] = new(big.Int).SetBytes(value.Bytes())
}
}
@ -303,7 +303,7 @@ func (ls *LendingStateDB) DumpLiquidationTimeTrie(orderBook common.Hash) (map[*b
it := trie.NewIterator(exhangeObject.getLiquidationTimeTrie(ls.db).NodeIterator(nil))
for it.Next() {
unixTimeHash := common.BytesToHash(it.Key)
if common.EmptyHash(unixTimeHash) {
if unixTimeHash.IsZero() {
continue
}
unixTime := new(big.Int).SetBytes(unixTimeHash.Bytes())
@ -346,7 +346,7 @@ func (ls *LendingStateDB) DumpLendingOrderTrie(orderBook common.Hash) (map[*big.
it := trie.NewIterator(exhangeObject.getLendingItemTrie(ls.db).NodeIterator(nil))
for it.Next() {
orderIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(orderIdHash) {
if orderIdHash.IsZero() {
continue
}
orderId := new(big.Int).SetBytes(orderIdHash.Bytes())
@ -386,7 +386,7 @@ func (ls *LendingStateDB) DumpLendingTradeTrie(orderBook common.Hash) (map[*big.
it := trie.NewIterator(exhangeObject.getLendingTradeTrie(ls.db).NodeIterator(nil))
for it.Next() {
tradeIdHash := common.BytesToHash(it.Key)
if common.EmptyHash(tradeIdHash) {
if tradeIdHash.IsZero() {
continue
}
tradeId := new(big.Int).SetBytes(tradeIdHash.Bytes())

View file

@ -70,19 +70,19 @@ func (s *lendingExchangeState) empty() bool {
if s.data.TradeNonce != 0 {
return false
}
if !common.EmptyHash(s.data.InvestingRoot) {
if !s.data.InvestingRoot.IsZero() {
return false
}
if !common.EmptyHash(s.data.BorrowingRoot) {
if !s.data.BorrowingRoot.IsZero() {
return false
}
if !common.EmptyHash(s.data.LendingItemRoot) {
if !s.data.LendingItemRoot.IsZero() {
return false
}
if !common.EmptyHash(s.data.LendingTradeRoot) {
if !s.data.LendingTradeRoot.IsZero() {
return false
}
if !common.EmptyHash(s.data.LiquidationTimeRoot) {
if !s.data.LiquidationTimeRoot.IsZero() {
return false
}
return true

View file

@ -116,7 +116,7 @@ func (lt *liquidationTimeState) getAllTradeIds(db Database) []common.Hash {
return tradeIds
}
for id, value := range lt.cachedStorage {
if !common.EmptyHash(value) {
if !value.IsZero() {
tradeIds = append(tradeIds, id)
}
}

View file

@ -343,7 +343,7 @@ func (ls *LendingStateDB) GetBestInvestingRate(orderBook common.Hash) (*big.Int,
stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil {
investingHash := stateObject.getBestInvestingInterest(ls.db)
if common.EmptyHash(investingHash) {
if investingHash.IsZero() {
return Zero, Zero
}
orderList := stateObject.getInvestingOrderList(ls.db, investingHash)
@ -360,7 +360,7 @@ func (ls *LendingStateDB) GetBestBorrowRate(orderBook common.Hash) (*big.Int, *b
stateObject := ls.getLendingExchange(orderBook)
if stateObject != nil {
priceHash := stateObject.getBestBorrowingInterest(ls.db)
if common.EmptyHash(priceHash) {
if priceHash.IsZero() {
return Zero, Zero
}
orderList := stateObject.getBorrowingOrderList(ls.db, priceHash)

View file

@ -581,7 +581,7 @@ func DoSettleBalance(coinbase common.Address, takerOrder, makerOrder *lendingsta
// masternodes only charge borrower relayer fee
matchingFee = new(big.Int).Add(matchingFee, common.RelayerLendingFee)
if common.EmptyHash(takerExOwner.Hash()) || common.EmptyHash(makerExOwner.Hash()) {
if takerExOwner.Hash().IsZero() || makerExOwner.Hash().IsZero() {
return fmt.Errorf("empty echange owner: taker: %v , maker : %v", takerExOwner, makerExOwner)
}
mapBalances := map[common.Address]map[common.Address]*big.Int{}

View file

@ -23,12 +23,13 @@ import (
"fmt"
"log"
"math/big"
"reflect"
"strings"
"testing"
"reflect"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/crypto"
)
@ -522,7 +523,7 @@ func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
strvalue = common.RightPadBytes([]byte(strin), 32)
fixedarrin1value1 = common.LeftPadBytes(fixedarrin1[0].Bytes(), 32)
fixedarrin1value2 = common.LeftPadBytes(fixedarrin1[1].Bytes(), 32)
dynarroffset = U256(big.NewInt(int64(256 + ((len(strin)/32)+1)*32)))
dynarroffset = math.U256Bytes(big.NewInt(int64(256 + ((len(strin)/32)+1)*32)))
dynarrlength = make([]byte, 32)
dynarrlength[31] = byte(len(dynarrin))
dynarrinvalue1 = common.LeftPadBytes(dynarrin[0].Bytes(), 32)
@ -620,16 +621,19 @@ func TestBareEvents(t *testing.T) {
}
// TestUnpackEvent is based on this contract:
// contract T {
// event received(address sender, uint amount, bytes memo);
// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
// receivedAddr(msg.sender);
// }
// }
//
// contract T {
// event received(address sender, uint amount, bytes memo);
// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
// receivedAddr(msg.sender);
// }
// }
//
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
//
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func TestUnpackEvent(t *testing.T) {
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON))
@ -709,7 +713,7 @@ func TestABI_MethodById(t *testing.T) {
}
b := fmt.Sprintf("%v", m2)
if a != b {
t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, common.ToHex(m.Id()))
t.Errorf("Method %v (id %v) not 'findable' by id in ABI", name, hexutil.Encode(m.Id()))
}
}

View file

@ -278,21 +278,20 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
return ret, nil
}
// capitalise makes the first character of a string upper case, also removing any
// prefixing underscores from the variable names.
func capitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
// ToCamelCase converts an under-score string to a camel-case string
func ToCamelCase(input string) string {
parts := strings.Split(input, "_")
for i, s := range parts {
if len(s) > 0 {
parts[i] = strings.ToUpper(s[:1]) + s[1:]
}
}
if len(input) == 0 {
return ""
}
return strings.ToUpper(input[:1]) + input[1:]
return strings.Join(parts, "")
}
// unpackStruct extracts each argument into its corresponding struct field
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
name := capitalise(arg.Name)
name := ToCamelCase(arg.Name)
typ := value.Type()
for j := 0; j < typ.NumField(); j++ {
// TODO read tags: `abi:"fieldName"`

View file

@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
gomath "math"
"math/big"
"os"
"sync"
@ -448,7 +449,10 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
call.GasPrice = new(big.Int)
if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 {
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, head.BaseFee), call.GasFeeCap)
call.GasPrice = new(big.Int).Add(call.GasTipCap, head.BaseFee)
if call.GasPrice.Cmp(call.GasFeeCap) > 0 {
call.GasPrice.Set(call.GasFeeCap)
}
}
}
}
@ -476,7 +480,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, txContext, statedb, nil, b.config, vm.Config{NoBaseFee: true})
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
gaspool := new(core.GasPool).AddGas(gomath.MaxUint64)
owner := common.Address{}
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
}

View file

@ -23,13 +23,14 @@ package bind
import (
"bytes"
"fmt"
"go/format"
"regexp"
"strings"
"text/template"
"unicode"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"golang.org/x/tools/imports"
"github.com/XinFinOrg/XDPoSChain/log"
)
// Lang is a target programming language selector to generate bindings for.
@ -43,10 +44,13 @@ const (
// to be used as is in client code, but rather as an intermediate struct which
// enforces compile time type safety and naming convention opposed to having to
// manually maintain hard coded strings that break on runtime.
func Bind(types []string, abis []string, bytecodes []string, pkg string, lang Lang) (string, error) {
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string) (string, error) {
// Process each individual contract requested binding
contracts := make(map[string]*tmplContract)
// Map used to flag each encountered library as such
isLib := make(map[string]struct{})
for i := 0; i < len(types); i++ {
// Parse the actual ABI to generate the binding for
evmABI, err := abi.JSON(strings.NewReader(abis[i]))
@ -115,20 +119,47 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
// Append the event to the accumulator list
events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
}
contracts[types[i]] = &tmplContract{
Type: capitalise(types[i]),
InputABI: strings.ReplaceAll(strippedABI, "\"", "\\\""),
InputBin: strings.TrimSpace(bytecodes[i]),
InputBin: strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"),
Constructor: evmABI.Constructor,
Calls: calls,
Transacts: transacts,
Events: events,
Libraries: make(map[string]string),
}
// Function 4-byte signatures are stored in the same sequence
// as types, if available.
if len(fsigs) > i {
contracts[types[i]].FuncSigs = fsigs[i]
}
// Parse library references.
for pattern, name := range libs {
matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin))
if err != nil {
log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
}
if matched {
contracts[types[i]].Libraries[pattern] = name
// keep track that this type is a library
if _, ok := isLib[name]; !ok {
isLib[name] = struct{}{}
}
}
}
}
// Check if that type has already been identified as a library
for i := 0; i < len(types); i++ {
_, ok := isLib[types[i]]
contracts[types[i]].Library = ok
}
// Generate the contract template data content and render it
data := &tmplData{
Package: pkg,
Contracts: contracts,
Libraries: libs,
}
buffer := new(bytes.Buffer)
@ -143,9 +174,9 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
if err := tmpl.Execute(buffer, data); err != nil {
return "", err
}
// For Go bindings pass the code through goimports to clean it up and double check
// For Go bindings pass the code through gofmt to clean it up
if lang == LangGo {
code, err := imports.Process(".", buffer.Bytes(), nil)
code, err := format.Source(buffer.Bytes())
if err != nil {
return "", fmt.Errorf("%v\n%s", err, buffer)
}
@ -161,139 +192,42 @@ var bindType = map[Lang]func(kind abi.Type) string{
LangGo: bindTypeGo,
}
// Helper function for the binding generators.
// It reads the unmatched characters after the inner type-match,
//
// (since the inner type is a prefix of the total type declaration),
// looks for valid arrays (possibly a dynamic one) wrapping the inner type,
// and returns the sizes of these arrays.
//
// Returned array sizes are in the same order as solidity signatures; inner array size first.
// Array sizes may also be "", indicating a dynamic array.
func wrapArray(stringKind string, innerLen int, innerMapping string) (string, []string) {
remainder := stringKind[innerLen:]
//find all the sizes
matches := regexp.MustCompile(`\[(\d*)\]`).FindAllStringSubmatch(remainder, -1)
parts := make([]string, 0, len(matches))
for _, match := range matches {
//get group 1 from the regex match
parts = append(parts, match[1])
}
return innerMapping, parts
}
// Translates the array sizes to a Go-lang declaration of a (nested) array of the inner type.
// Simply returns the inner type if arraySizes is empty.
func arrayBindingGo(inner string, arraySizes []string) string {
out := ""
//prepend all array sizes, from outer (end arraySizes) to inner (start arraySizes)
for i := len(arraySizes) - 1; i >= 0; i-- {
out += "[" + arraySizes[i] + "]"
}
out += inner
return out
}
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. *big.Int).
func bindTypeGo(kind abi.Type) string {
stringKind := kind.String()
innerLen, innerMapping := bindUnnestedTypeGo(stringKind)
return arrayBindingGo(wrapArray(stringKind, innerLen, innerMapping))
}
// The inner function of bindTypeGo, this finds the inner type of stringKind.
// (Or just the type itself if it is not an array or slice)
// The length of the matched part is returned, with the the translated type.
func bindUnnestedTypeGo(stringKind string) (int, string) {
switch {
case strings.HasPrefix(stringKind, "address"):
return len("address"), "common.Address"
case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
return len(parts[0]), fmt.Sprintf("[%s]byte", parts[1])
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
// bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go one.
func bindBasicTypeGo(kind abi.Type) string {
switch kind.T {
case abi.AddressTy:
return "common.Address"
case abi.IntTy, abi.UintTy:
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String())
switch parts[2] {
case "8", "16", "32", "64":
return len(parts[0]), fmt.Sprintf("%sint%s", parts[1], parts[2])
return fmt.Sprintf("%sint%s", parts[1], parts[2])
}
return len(parts[0]), "*big.Int"
case strings.HasPrefix(stringKind, "bool"):
return len("bool"), "bool"
case strings.HasPrefix(stringKind, "string"):
return len("string"), "string"
return "*big.Int"
case abi.FixedBytesTy:
return fmt.Sprintf("[%d]byte", kind.Size)
case abi.BytesTy:
return "[]byte"
case abi.FunctionTy:
return "[24]byte"
default:
return len(stringKind), stringKind
// string, bool types
return kind.String()
}
}
// Translates the array sizes to a Java declaration of a (nested) array of the inner type.
// Simply returns the inner type if arraySizes is empty.
func arrayBindingJava(inner string, arraySizes []string) string {
// Java array type declarations do not include the length.
return inner + strings.Repeat("[]", len(arraySizes))
}
// The inner function of bindTypeJava, this finds the inner type of stringKind.
// (Or just the type itself if it is not an array or slice)
// The length of the matched part is returned, with the the translated type.
func bindUnnestedTypeJava(stringKind string) (int, string) {
switch {
case strings.HasPrefix(stringKind, "address"):
parts := regexp.MustCompile(`address(\[[0-9]*\])?`).FindStringSubmatch(stringKind)
if len(parts) != 2 {
return len(stringKind), stringKind
}
if parts[1] == "" {
return len("address"), "Address"
}
return len(parts[0]), "Addresses"
case strings.HasPrefix(stringKind, "bytes"):
parts := regexp.MustCompile(`bytes([0-9]*)`).FindStringSubmatch(stringKind)
if len(parts) != 2 {
return len(stringKind), stringKind
}
return len(parts[0]), "byte[]"
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
//Note that uint and int (without digits) are also matched,
// these are size 256, and will translate to BigInt (the default).
parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(stringKind)
if len(parts) != 3 {
return len(stringKind), stringKind
}
namedSize := map[string]string{
"8": "byte",
"16": "short",
"32": "int",
"64": "long",
}[parts[2]]
//default to BigInt
if namedSize == "" {
namedSize = "BigInt"
}
return len(parts[0]), namedSize
case strings.HasPrefix(stringKind, "bool"):
return len("bool"), "boolean"
case strings.HasPrefix(stringKind, "string"):
return len("string"), "String"
// bindTypeGo converts solidity types to Go ones. Since there is no clear mapping
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
// mapped will use an upscaled type (e.g. BigDecimal).
func bindTypeGo(kind abi.Type) string {
// todo(rjl493456442) tuple
switch kind.T {
case abi.ArrayTy:
return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem)
case abi.SliceTy:
return "[]" + bindTypeGo(*kind.Elem)
default:
return len(stringKind), stringKind
return bindBasicTypeGo(kind)
}
}
@ -322,53 +256,22 @@ var namedType = map[Lang]func(string, abi.Type) string{
// methodNormalizer is a name transformer that modifies Solidity method names to
// conform to target language naming concentions.
var methodNormalizer = map[Lang]func(string) string{
LangGo: capitalise,
LangGo: abi.ToCamelCase,
}
// capitalise makes a camel-case string which starts with an upper case character.
func capitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
}
if len(input) == 0 {
return ""
}
return toCamelCase(strings.ToUpper(input[:1]) + input[1:])
return abi.ToCamelCase(input)
}
// decapitalise makes a camel-case string which starts with a lower case character.
func decapitalise(input string) string {
for len(input) > 0 && input[0] == '_' {
input = input[1:]
}
if len(input) == 0 {
return ""
return input
}
return toCamelCase(strings.ToLower(input[:1]) + input[1:])
}
// toCamelCase converts an under-score string to a camel-case string
func toCamelCase(input string) string {
toupper := false
result := ""
for k, v := range input {
switch {
case k == 0:
result = strings.ToUpper(string(input[0]))
case toupper:
result += strings.ToUpper(string(v))
toupper = false
case v == '_':
toupper = true
default:
result += string(v)
}
}
return result
goForm := abi.ToCamelCase(input)
return strings.ToLower(goForm[:1]) + goForm[1:]
}
// structured checks whether a list of ABI data types has enough information to

File diff suppressed because one or more lines are too long

View file

@ -22,6 +22,7 @@ import "github.com/XinFinOrg/XDPoSChain/accounts/abi"
type tmplData struct {
Package string // Name of the package to place the generated file in
Contracts map[string]*tmplContract // List of contracts to generate into this file
Libraries map[string]string // Map the bytecode's link pattern to the library name
}
// tmplContract contains the data needed to generate an individual contract binding.
@ -29,10 +30,13 @@ type tmplContract struct {
Type string // Type name of the main contract binding
InputABI string // JSON ABI used as the input to generate the binding from
InputBin string // Optional EVM bytecode used to denetare deploy code from
FuncSigs map[string]string // Optional map: string signature -> 4-byte signature
Constructor abi.Method // Contract constructor for deploy parametrization
Calls map[string]*tmplMethod // Contract calls that only read state data
Transacts map[string]*tmplMethod // Contract calls that write state data
Events map[string]*tmplEvent // Contract events accessors
Libraries map[string]string // Same as tmplData, but filtered to only keep what the contract needs
Library bool
}
// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed
@ -63,13 +67,44 @@ const tmplSourceGo = `
package {{.Package}}
import (
"math/big"
"strings"
ethereum "github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts/abi"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/event"
)
// Reference imports to suppress errors if they are not otherwise used.
var (
_ = big.NewInt
_ = strings.NewReader
_ = ethereum.ErrNotFound
_ = bind.Bind
_ = common.Big1
_ = types.BloomLookup
_ = event.NewSubscription
)
{{range $contract := .Contracts}}
// {{.Type}}ABI is the input ABI used to generate the binding from.
const {{.Type}}ABI = "{{.InputABI}}"
{{if $contract.FuncSigs}}
// {{.Type}}FuncSigs maps the 4-byte function signature to its string representation.
var {{.Type}}FuncSigs = map[string]string{
{{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}",
{{end}}
}
{{end}}
{{if .InputBin}}
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
const {{.Type}}Bin = ` + "`" + `{{.InputBin}}` + "`" + `
var {{.Type}}Bin = "0x{{.InputBin}}"
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
@ -77,6 +112,10 @@ package {{.Package}}
if err != nil {
return common.Address{}, nil, nil, err
}
{{range $pattern, $name := .Libraries}}
{{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend)
{{$contract.Type}}Bin = strings.Replace({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:], -1)
{{end}}
address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}})
if err != nil {
return common.Address{}, nil, nil, err

View file

@ -21,7 +21,6 @@ import (
"reflect"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
)
var (
@ -44,11 +43,6 @@ var (
int64_ts = reflect.TypeOf([]int64(nil))
)
// U256 converts a big Int into a 256bit EVM number.
func U256(n *big.Int) []byte {
return math.PaddedBigBytes(math.U256(n), 32)
}
// checks whether the given reflect value is signed. This also works for slices with a number type
func isSigned(v reflect.Value) bool {
switch v.Type() {

View file

@ -69,11 +69,11 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return U256(new(big.Int).SetUint64(value.Uint()))
return math.U256Bytes(new(big.Int).SetUint64(value.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return U256(big.NewInt(value.Int()))
return math.U256Bytes(big.NewInt(value.Int()))
case reflect.Ptr:
return U256(value.Interface().(*big.Int))
return math.U256Bytes(value.Interface().(*big.Int))
default:
panic("abi: fatal error")
}

View file

@ -116,7 +116,7 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
func requireUniqueStructFieldNames(args Arguments) error {
exists := make(map[string]bool)
for _, arg := range args {
field := capitalise(arg.Name)
field := ToCamelCase(arg.Name)
if field == "" {
return errors.New("abi: purely underscored output cannot unpack to struct")
}

View file

@ -273,6 +273,53 @@ var unpackTests = []unpackTest{
Int2 *big.Int
}{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"name":"int_one","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int__one","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int_one_","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
}{big.NewInt(1)},
},
{
def: `[{"name":"int_one","type":"int256"}, {"name":"intone","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
Intone *big.Int
}{big.NewInt(1), big.NewInt(2)},
},
{
def: `[{"name":"___","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
IntOne *big.Int
Intone *big.Int
}{},
err: "abi: purely underscored output cannot unpack to struct",
},
{
def: `[{"name":"int_one","type":"int256"},{"name":"IntOne","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
Int2 *big.Int
}{},
err: "abi: multiple outputs mapping to the same struct field 'IntOne'",
},
{
def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",

View file

@ -16,7 +16,7 @@
// This file contains the implementation for interacting with the Ledger hardware
// wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
// https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
// https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.adoc
package usbwallet

67
beacon/merkle/merkle.go Normal file
View file

@ -0,0 +1,67 @@
// Copyright 2022 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 merkle implements proof verifications in binary merkle trees.
package merkle
import (
"crypto/sha256"
"errors"
"reflect"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
)
// Value represents either a 32 byte leaf value or hash node in a binary merkle tree/partial proof.
type Value [32]byte
// Values represent a series of merkle tree leaves/nodes.
type Values []Value
var valueT = reflect.TypeOf(Value{})
// UnmarshalJSON parses a merkle value in hex syntax.
func (m *Value) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(valueT, input, m[:])
}
// VerifyProof verifies a Merkle proof branch for a single value in a
// binary Merkle tree (index is a generalized tree index).
func VerifyProof(root common.Hash, index uint64, branch Values, value Value) error {
hasher := sha256.New()
for _, sibling := range branch {
hasher.Reset()
if index&1 == 0 {
hasher.Write(value[:])
hasher.Write(sibling[:])
} else {
hasher.Write(sibling[:])
hasher.Write(value[:])
}
hasher.Sum(value[:0])
if index >>= 1; index == 0 {
return errors.New("branch has extra items")
}
}
if index != 1 {
return errors.New("branch is missing items")
}
if common.Hash(value) != root {
return errors.New("root mismatch")
}
return nil
}

View file

@ -1,4 +1,4 @@
// Copyright 2014 The go-ethereum Authors
// Copyright 2022 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
@ -14,12 +14,31 @@
// 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 common
package params
import (
"testing"
const (
EpochLength = 32
SyncPeriodLength = 8192
checker "gopkg.in/check.v1"
BLSSignatureSize = 96
BLSPubkeySize = 48
SyncCommitteeSize = 512
SyncCommitteeBitmaskSize = SyncCommitteeSize / 8
SyncCommitteeSupermajority = (SyncCommitteeSize*2 + 2) / 3
)
func Test(t *testing.T) { checker.TestingT(t) }
const (
StateIndexGenesisTime = 32
StateIndexGenesisValidators = 33
StateIndexForkVersion = 141
StateIndexLatestHeader = 36
StateIndexBlockRoots = 37
StateIndexStateRoots = 38
StateIndexHistoricRoots = 39
StateIndexFinalBlock = 105
StateIndexSyncCommittee = 54
StateIndexNextSyncCommittee = 55
StateIndexExecPayload = 56
StateIndexExecHead = 908
)

214
beacon/types/committee.go Normal file
View file

@ -0,0 +1,214 @@
// Copyright 2023 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 (
"crypto/sha256"
"encoding/json"
"fmt"
"math/bits"
"github.com/XinFinOrg/XDPoSChain/beacon/params"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
bls "github.com/protolambda/bls12-381-util"
)
// SerializedSyncCommitteeSize is the size of the sync committee plus the
// aggregate public key.
const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize
// SerializedSyncCommittee is the serialized version of a sync committee
// plus the aggregate public key.
type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte
// jsonSyncCommittee is the JSON representation of a sync committee.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type jsonSyncCommittee struct {
Pubkeys []hexutil.Bytes `json:"pubkeys"`
Aggregate hexutil.Bytes `json:"aggregate_pubkey"`
}
// MarshalJSON implements json.Marshaler.
func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) {
sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)}
for i := range sc.Pubkeys {
sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize)
copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
}
sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize)
copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:])
return json.Marshal(&sc)
}
// UnmarshalJSON implements json.Marshaler.
func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error {
var sc jsonSyncCommittee
if err := json.Unmarshal(input, &sc); err != nil {
return err
}
if len(sc.Pubkeys) != params.SyncCommitteeSize {
return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys))
}
for i, key := range sc.Pubkeys {
if len(key) != params.BLSPubkeySize {
return fmt.Errorf("pubkey %d has invalid size %d", i, len(key))
}
copy(s[i*params.BLSPubkeySize:], key[:])
}
if len(sc.Aggregate) != params.BLSPubkeySize {
return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate))
}
copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:])
return nil
}
// Root calculates the root hash of the binary tree representation of a sync
// committee provided in serialized format.
//
// TODO(zsfelfoldi): Get rid of this when SSZ encoding lands.
func (s *SerializedSyncCommittee) Root() common.Hash {
var (
hasher = sha256.New()
padding [64 - params.BLSPubkeySize]byte
data [params.SyncCommitteeSize]common.Hash
l = params.SyncCommitteeSize
)
for i := range data {
hasher.Reset()
hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize])
hasher.Write(padding[:])
hasher.Sum(data[i][:0])
}
for l > 1 {
for i := 0; i < l/2; i++ {
hasher.Reset()
hasher.Write(data[i*2][:])
hasher.Write(data[i*2+1][:])
hasher.Sum(data[i][:0])
}
l /= 2
}
hasher.Reset()
hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize])
hasher.Write(padding[:])
hasher.Sum(data[1][:0])
hasher.Reset()
hasher.Write(data[0][:])
hasher.Write(data[1][:])
hasher.Sum(data[0][:0])
return data[0]
}
// Deserialize splits open the pubkeys into proper BLS key types.
func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) {
sc := new(SyncCommittee)
for i := 0; i <= params.SyncCommitteeSize; i++ {
key := new(bls.Pubkey)
var bytes [params.BLSPubkeySize]byte
copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
if err := key.Deserialize(&bytes); err != nil {
return nil, err
}
if i < params.SyncCommitteeSize {
sc.keys[i] = key
} else {
sc.aggregate = key
}
}
return sc, nil
}
// SyncCommittee is a set of sync committee signer pubkeys and the aggregate key.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type SyncCommittee struct {
keys [params.SyncCommitteeSize]*bls.Pubkey
aggregate *bls.Pubkey
}
// VerifySignature returns true if the given sync aggregate is a valid signature
// or the given hash.
func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool {
var (
sig bls.Signature
keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize)
)
if err := sig.Deserialize(&signature.Signature); err != nil {
return false
}
for i, key := range sc.keys {
if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 {
keys = append(keys, key)
}
}
return bls.FastAggregateVerify(keys, signingRoot[:], &sig)
}
// SyncAggregate represents an aggregated BLS signature with Signers referring
// to a subset of the corresponding sync committee.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type SyncAggregate struct {
Signers [params.SyncCommitteeBitmaskSize]byte
Signature [params.BLSSignatureSize]byte
}
type jsonSyncAggregate struct {
Signers hexutil.Bytes `json:"sync_committee_bits"`
Signature hexutil.Bytes `json:"sync_committee_signature"`
}
// MarshalJSON implements json.Marshaler.
func (s *SyncAggregate) MarshalJSON() ([]byte, error) {
return json.Marshal(&jsonSyncAggregate{
Signers: s.Signers[:],
Signature: s.Signature[:],
})
}
// UnmarshalJSON implements json.Marshaler.
func (s *SyncAggregate) UnmarshalJSON(input []byte) error {
var sc jsonSyncAggregate
if err := json.Unmarshal(input, &sc); err != nil {
return err
}
if len(sc.Signers) != params.SyncCommitteeBitmaskSize {
return fmt.Errorf("invalid signature bitmask size %d", len(sc.Signers))
}
if len(sc.Signature) != params.BLSSignatureSize {
return fmt.Errorf("invalid signature size %d", len(sc.Signature))
}
copy(s.Signers[:], sc.Signers)
copy(s.Signature[:], sc.Signature)
return nil
}
// SignerCount returns the number of signers in the aggregate signature.
func (s *SyncAggregate) SignerCount() int {
var count int
for _, v := range s.Signers {
count += bits.OnesCount8(v)
}
return count
}

176
beacon/types/config.go Normal file
View file

@ -0,0 +1,176 @@
// Copyright 2022 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 (
"crypto/sha256"
"fmt"
"os"
"sort"
"strconv"
"strings"
"github.com/XinFinOrg/XDPoSChain/beacon/merkle"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/go-yaml/yaml"
)
// syncCommitteeDomain specifies the signatures specific use to avoid clashes
// across signing different data structures.
const syncCommitteeDomain = 7
// Fork describes a single beacon chain fork and also stores the calculated
// signature domain used after this fork.
type Fork struct {
// Name of the fork in the chain config (config.yaml) file{
Name string
// Epoch when given fork version is activated
Epoch uint64
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
Version []byte
// calculated by computeDomain, based on fork version and genesis validators root
domain merkle.Value
}
// computeDomain returns the signature domain based on the given fork version
// and genesis validator set root.
func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
var (
hasher = sha256.New()
forkVersion32 merkle.Value
forkDataRoot merkle.Value
)
copy(forkVersion32[:], f.Version)
hasher.Write(forkVersion32[:])
hasher.Write(genesisValidatorsRoot[:])
hasher.Sum(forkDataRoot[:0])
f.domain[0] = syncCommitteeDomain
copy(f.domain[4:], forkDataRoot[:28])
}
// Forks is the list of all beacon chain forks in the chain configuration.
type Forks []*Fork
// domain returns the signature domain for the given epoch (assumes that domains
// have already been calculated).
func (f Forks) domain(epoch uint64) (merkle.Value, error) {
for i := len(f) - 1; i >= 0; i-- {
if epoch >= f[i].Epoch {
return f[i].domain, nil
}
}
return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
}
// SigningRoot calculates the signing root of the given header.
func (f Forks) SigningRoot(header Header) (common.Hash, error) {
domain, err := f.domain(header.Epoch())
if err != nil {
return common.Hash{}, err
}
var (
signingRoot common.Hash
headerHash = header.Hash()
hasher = sha256.New()
)
hasher.Write(headerHash[:])
hasher.Write(domain[:])
hasher.Sum(signingRoot[:0])
return signingRoot, nil
}
func (f Forks) Len() int { return len(f) }
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch }
// ChainConfig contains the beacon chain configuration.
type ChainConfig struct {
GenesisTime uint64 // Unix timestamp of slot 0
GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation
Forks Forks
}
// AddFork adds a new item to the list of forks.
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
fork := &Fork{
Name: name,
Epoch: epoch,
Version: version,
}
fork.computeDomain(c.GenesisValidatorsRoot)
c.Forks = append(c.Forks, fork)
sort.Sort(c.Forks)
return c
}
// LoadForks parses the beacon chain configuration file (config.yaml) and extracts
// the list of forks.
func (c *ChainConfig) LoadForks(path string) error {
file, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read beacon chain config file: %v", err)
}
config := make(map[string]string)
if err := yaml.Unmarshal(file, &config); err != nil {
return fmt.Errorf("failed to parse beacon chain config file: %v", err)
}
var (
versions = make(map[string][]byte)
epochs = make(map[string]uint64)
)
epochs["GENESIS"] = 0
for key, value := range config {
if strings.HasSuffix(key, "_FORK_VERSION") {
name := key[:len(key)-len("_FORK_VERSION")]
if v, err := hexutil.Decode(value); err == nil {
versions[name] = v
} else {
return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err)
}
}
if strings.HasSuffix(key, "_FORK_EPOCH") {
name := key[:len(key)-len("_FORK_EPOCH")]
if v, err := strconv.ParseUint(value, 10, 64); err == nil {
epochs[name] = v
} else {
return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err)
}
}
}
for name, epoch := range epochs {
if version, ok := versions[name]; ok {
delete(versions, name)
c.AddFork(name, epoch, version)
} else {
return fmt.Errorf("fork id missing for %q in beacon chain config file", name)
}
}
for name := range versions {
return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name)
}
sort.Sort(c.Forks)
return nil
}

View file

@ -0,0 +1,66 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/XinFinOrg/XDPoSChain/common"
)
var _ = (*headerMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (h Header) MarshalJSON() ([]byte, error) {
type Header struct {
Slot common.Decimal `gencodec:"required" json:"slot"`
ProposerIndex common.Decimal `gencodec:"required" json:"proposer_index"`
ParentRoot common.Hash `gencodec:"required" json:"parent_root"`
StateRoot common.Hash `gencodec:"required" json:"state_root"`
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
}
var enc Header
enc.Slot = common.Decimal(h.Slot)
enc.ProposerIndex = common.Decimal(h.ProposerIndex)
enc.ParentRoot = h.ParentRoot
enc.StateRoot = h.StateRoot
enc.BodyRoot = h.BodyRoot
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (h *Header) UnmarshalJSON(input []byte) error {
type Header struct {
Slot *common.Decimal `gencodec:"required" json:"slot"`
ProposerIndex *common.Decimal `gencodec:"required" json:"proposer_index"`
ParentRoot *common.Hash `gencodec:"required" json:"parent_root"`
StateRoot *common.Hash `gencodec:"required" json:"state_root"`
BodyRoot *common.Hash `gencodec:"required" json:"body_root"`
}
var dec Header
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Slot == nil {
return errors.New("missing required field 'slot' for Header")
}
h.Slot = uint64(*dec.Slot)
if dec.ProposerIndex == nil {
return errors.New("missing required field 'proposer_index' for Header")
}
h.ProposerIndex = uint64(*dec.ProposerIndex)
if dec.ParentRoot == nil {
return errors.New("missing required field 'parent_root' for Header")
}
h.ParentRoot = *dec.ParentRoot
if dec.StateRoot == nil {
return errors.New("missing required field 'state_root' for Header")
}
h.StateRoot = *dec.StateRoot
if dec.BodyRoot == nil {
return errors.New("missing required field 'body_root' for Header")
}
h.BodyRoot = *dec.BodyRoot
return nil
}

121
beacon/types/header.go Normal file
View file

@ -0,0 +1,121 @@
// Copyright 2022 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 implements a few types of the beacon chain for light client usage.
package types
import (
"crypto/sha256"
"encoding/binary"
"github.com/XinFinOrg/XDPoSChain/beacon/merkle"
"github.com/XinFinOrg/XDPoSChain/beacon/params"
"github.com/XinFinOrg/XDPoSChain/common"
)
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
const (
headerIndexSlot = 8
headerIndexProposerIndex = 9
headerIndexParentRoot = 10
headerIndexStateRoot = 11
headerIndexBodyRoot = 12
)
// Header defines a beacon header.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
type Header struct {
// Monotonically increasing slot number for the beacon block (may be gapped)
Slot uint64 `gencodec:"required" json:"slot"`
// Index into the validator table who created the beacon block
ProposerIndex uint64 `gencodec:"required" json:"proposer_index"`
// SSZ hash of the parent beacon header
ParentRoot common.Hash `gencodec:"required" json:"parent_root"`
// SSZ hash of the beacon state (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beacon-state)
StateRoot common.Hash `gencodec:"required" json:"state_root"`
// SSZ hash of the beacon block body (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconblockbody)
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
}
// headerMarshaling is a field type overrides for gencodec.
type headerMarshaling struct {
Slot common.Decimal
ProposerIndex common.Decimal
}
// Hash calculates the block root of the header.
//
// TODO(zsfelfoldi): Remove this when an SSZ encoder lands.
func (h *Header) Hash() common.Hash {
var values [16]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree
binary.LittleEndian.PutUint64(values[headerIndexSlot][:8], h.Slot)
binary.LittleEndian.PutUint64(values[headerIndexProposerIndex][:8], h.ProposerIndex)
values[headerIndexParentRoot] = merkle.Value(h.ParentRoot)
values[headerIndexStateRoot] = merkle.Value(h.StateRoot)
values[headerIndexBodyRoot] = merkle.Value(h.BodyRoot)
hasher := sha256.New()
for i := 7; i > 0; i-- {
hasher.Reset()
hasher.Write(values[i*2][:])
hasher.Write(values[i*2+1][:])
hasher.Sum(values[i][:0])
}
return common.Hash(values[1])
}
// Epoch returns the epoch the header belongs to.
func (h *Header) Epoch() uint64 {
return h.Slot / params.EpochLength
}
// SyncPeriod returns the sync period the header belongs to.
func (h *Header) SyncPeriod() uint64 {
return SyncPeriod(h.Slot)
}
// SyncPeriodStart returns the first slot of the given period.
func SyncPeriodStart(period uint64) uint64 {
return period * params.SyncPeriodLength
}
// SyncPeriod returns the sync period that the given slot belongs to.
func SyncPeriod(slot uint64) uint64 {
return slot / params.SyncPeriodLength
}
// SignedHeader represents a beacon header signed by a sync committee.
//
// This structure is created from either an optimistic update or an instant update:
// - https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
// - https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml
type SignedHeader struct {
// Beacon header being signed
Header Header
// Sync committee BLS signature aggregate
Signature SyncAggregate
// Slot in which the signature has been created (newer than Header.Slot,
// determines the signing sync committee)
SignatureSlot uint64
}

118
beacon/types/update.go Normal file
View file

@ -0,0 +1,118 @@
// Copyright 2022 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 (
"errors"
"fmt"
"github.com/XinFinOrg/XDPoSChain/beacon/merkle"
"github.com/XinFinOrg/XDPoSChain/beacon/params"
"github.com/XinFinOrg/XDPoSChain/common"
)
// LightClientUpdate is a proof of the next sync committee root based on a header
// signed by the sync committee of the given period. Optionally, the update can
// prove quasi-finality by the signed header referring to a previous, finalized
// header from the same period, and the finalized header referring to the next
// sync committee root.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
type LightClientUpdate struct {
AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee
NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one
NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality
FinalityBranch merkle.Values // Proof for the announced finality
score *UpdateScore // Weight of the update to compare between competing ones
}
// Validate verifies the validity of the update.
func (update *LightClientUpdate) Validate() error {
period := update.AttestedHeader.Header.SyncPeriod()
if SyncPeriod(update.AttestedHeader.SignatureSlot) != period {
return errors.New("signature slot and signed header are from different periods")
}
if update.FinalizedHeader != nil {
if update.FinalizedHeader.SyncPeriod() != period {
return errors.New("finalized header is from different period")
}
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
return fmt.Errorf("invalid finalized header proof: %w", err)
}
}
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
return fmt.Errorf("invalid next sync committee proof: %w", err)
}
return nil
}
// Score returns the UpdateScore describing the proof strength of the update
// Note: thread safety can be ensured by always calling Score on a newly received
// or decoded update before making it potentially available for other threads
func (update *LightClientUpdate) Score() UpdateScore {
if update.score == nil {
update.score = &UpdateScore{
SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()),
SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff),
FinalizedHeader: update.FinalizedHeader != nil,
}
}
return *update.score
}
// UpdateScore allows the comparison between updates at the same period in order
// to find the best update chain that provides the strongest proof of being canonical.
//
// UpdateScores have a tightly packed binary encoding format for efficient p2p
// protocol transmission. Each UpdateScore is encoded in 3 bytes.
// When interpreted as a 24 bit little indian unsigned integer:
// - the lowest 10 bits contain the number of signers in the header signature aggregate
// - the next 13 bits contain the "sub-period index" which is he signed header's
// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being
// re-orged before the previous period boundary in case of non-finalized updates)
// - the highest bit is set when the update is finalized (meaning that the finality
// header referenced by the signed header is in the same period as the signed
// header, making reorgs before the period boundary impossible
type UpdateScore struct {
SignerCount uint32 // number of signers in the header signature aggregate
SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength
FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures
}
// finalized returns true if the update has a header signed by at least 2/3 of
// the committee, referring to a finalized header that refers to the next sync
// committee. This condition is a close approximation of the actual finality
// condition that can only be verified by full beacon nodes.
func (u *UpdateScore) finalized() bool {
return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority
}
// BetterThan returns true if update u is considered better than w.
func (u UpdateScore) BetterThan(w UpdateScore) bool {
var (
uFinalized = u.finalized()
wFinalized = w.finalized()
)
if uFinalized != wFinalized {
return uFinalized
}
return u.SignerCount > w.SignerCount
}

View file

@ -19,11 +19,14 @@ package main
import (
"encoding/json"
"fmt"
"io"
"os"
"strings"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common/compiler"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/internal/flags"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/urfave/cli/v2"
@ -50,14 +53,9 @@ var (
Name: "type",
Usage: "Struct name for the binding (default = package name)",
}
solFlag = &cli.StringFlag{
Name: "sol",
Usage: "Path to the Ethereum contract Solidity source to build and bind",
}
solcFlag = &cli.StringFlag{
Name: "solc",
Usage: "Solidity compiler to use if source builds are requested",
Value: "solc",
jsonFlag = &cli.StringFlag{
Name: "combined-json",
Usage: "Path to the combined-json file generated by compiler",
}
excFlag = &cli.StringFlag{
Name: "exc",
@ -85,8 +83,7 @@ func init() {
abiFlag,
binFlag,
typeFlag,
solFlag,
solcFlag,
jsonFlag,
excFlag,
pkgFlag,
outFlag,
@ -96,68 +93,43 @@ func init() {
}
func abigen(c *cli.Context) error {
if c.String(abiFlag.Name) == "" && c.String(solFlag.Name) == "" {
fmt.Printf("No contract ABI (--abi) or Solidity source (--sol) specified\n")
os.Exit(-1)
} else if (c.String(abiFlag.Name) != "" || c.String(binFlag.Name) != "" || c.String(typeFlag.Name) != "") && c.String(solFlag.Name) != "" {
fmt.Printf("Contract ABI (--abi), bytecode (--bin) and type (--type) flags are mutually exclusive with the Solidity source (--sol) flag\n")
os.Exit(-1)
}
utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected.
if c.String(pkgFlag.Name) == "" {
fmt.Printf("No destination package specified (--pkg)\n")
os.Exit(-1)
}
var lang bind.Lang
switch c.String(langFlag.Name) {
case "go":
lang = bind.LangGo
default:
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", c.String(langFlag.Name))
os.Exit(-1)
utils.Fatalf("No destination package specified (--pkg)")
}
lang := bind.LangGo
// If the entire solidity code was specified, build and bind based on that
var (
abis []string
bins []string
types []string
sigs []map[string]string
libs = make(map[string]string)
)
if c.String(solFlag.Name) != "" {
// Generate the list of types to exclude from binding
exclude := make(map[string]bool)
for _, kind := range strings.Split(c.String(excFlag.Name), ",") {
exclude[strings.ToLower(kind)] = true
if c.String(abiFlag.Name) != "" {
// Load up the ABI, optional bytecode and type name from the parameters
var (
abi []byte
err error
)
input := c.String(abiFlag.Name)
if input == "-" {
abi, err = io.ReadAll(os.Stdin)
} else {
abi, err = os.ReadFile(input)
}
contracts, err := compiler.CompileSolidity(c.String(solcFlag.Name), c.String(solFlag.Name))
if err != nil {
fmt.Printf("Failed to build Solidity contract: %v\n", err)
os.Exit(-1)
}
// Gather all non-excluded contract for binding
for name, contract := range contracts {
if exclude[strings.ToLower(name)] {
continue
}
abi, _ := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse
abis = append(abis, string(abi))
bins = append(bins, contract.Code)
nameParts := strings.Split(name, ":")
types = append(types, nameParts[len(nameParts)-1])
}
} else {
// Otherwise load up the ABI, optional bytecode and type name from the parameters
abi, err := os.ReadFile(c.String(abiFlag.Name))
if err != nil {
fmt.Printf("Failed to read input ABI: %v\n", err)
os.Exit(-1)
utils.Fatalf("Failed to read input ABI: %v", err)
}
abis = append(abis, string(abi))
bin := []byte{}
if c.String(binFlag.Name) != "" {
if bin, err = os.ReadFile(c.String(binFlag.Name)); err != nil {
fmt.Printf("Failed to read input bytecode: %v\n", err)
os.Exit(-1)
var bin []byte
if binFile := c.String(binFlag.Name); binFile != "" {
if bin, err = os.ReadFile(binFile); err != nil {
utils.Fatalf("Failed to read input bytecode: %v", err)
}
if strings.Contains(string(bin), "//") {
utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos")
}
}
bins = append(bins, string(bin))
@ -167,21 +139,55 @@ func abigen(c *cli.Context) error {
kind = c.String(pkgFlag.Name)
}
types = append(types, kind)
} else {
// Generate the list of types to exclude from binding
exclude := make(map[string]bool)
for _, kind := range strings.Split(c.String(excFlag.Name), ",") {
exclude[strings.ToLower(kind)] = true
}
var contracts map[string]*compiler.Contract
if c.IsSet(jsonFlag.Name) {
jsonOutput, err := os.ReadFile(c.String(jsonFlag.Name))
if err != nil {
utils.Fatalf("Failed to read combined-json from compiler: %v", err)
}
contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "")
if err != nil {
utils.Fatalf("Failed to read contract information from json output: %v", err)
}
}
// Gather all non-excluded contract for binding
for name, contract := range contracts {
if exclude[strings.ToLower(name)] {
continue
}
abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse
if err != nil {
utils.Fatalf("Failed to parse ABIs from compiler output: %v", err)
}
abis = append(abis, string(abi))
bins = append(bins, contract.Code)
sigs = append(sigs, contract.Hashes)
nameParts := strings.Split(name, ":")
types = append(types, nameParts[len(nameParts)-1])
libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36]
libs[libPattern] = nameParts[len(nameParts)-1]
}
}
// Generate the contract binding
code, err := bind.Bind(types, abis, bins, c.String(pkgFlag.Name), lang)
code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs)
if err != nil {
fmt.Printf("Failed to generate ABI binding: %v\n", err)
os.Exit(-1)
utils.Fatalf("Failed to generate ABI binding: %v", err)
}
// Either flush it out to a file or display on the standard output
if c.String(outFlag.Name) == "" {
if !c.IsSet(outFlag.Name) {
fmt.Printf("%s\n", code)
return nil
}
if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil {
fmt.Printf("Failed to write ABI binding: %v\n", err)
os.Exit(-1)
utils.Fatalf("Failed to write ABI binding: %v", err)
}
return nil
}

View file

@ -298,7 +298,7 @@ var (
CacheGCFlag = &cli.IntFlag{
Name: "cache-gc",
Aliases: []string{"cache.gc"},
Usage: "Percentage of cache memory allowance to use for trie pruning",
Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
Value: 25,
Category: flags.PerfCategory,
}
@ -1024,7 +1024,7 @@ func setWS(ctx *cli.Context, cfg *node.Config) {
// setIPC creates an IPC path configuration from the set command line flags,
// returning an empty string if IPC was explicitly disabled, or the set path.
func setIPC(ctx *cli.Context, cfg *node.Config) {
checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
switch {
case ctx.Bool(IPCDisabledFlag.Name):
cfg.IPCPath = ""
@ -1034,7 +1034,7 @@ func setIPC(ctx *cli.Context, cfg *node.Config) {
}
func setPrefix(ctx *cli.Context, cfg *node.Config) {
checkExclusive(ctx, Enable0xPrefixFlag, EnableXDCPrefixFlag)
CheckExclusive(ctx, Enable0xPrefixFlag, EnableXDCPrefixFlag)
}
// MakeDatabaseHandles raises out the number of allowed file handles per process
@ -1301,10 +1301,10 @@ func setEthash(ctx *cli.Context, cfg *ethconfig.Config) {
}
}
// checkExclusive verifies that only a single isntance of the provided flags was
// CheckExclusive verifies that only a single isntance of the provided flags was
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
func checkExclusive(ctx *cli.Context, args ...interface{}) {
func CheckExclusive(ctx *cli.Context, args ...interface{}) {
set := make([]string, 0, 1)
for i := 0; i < len(args); i++ {
// Make sure the next argument is a flag and skip if not set
@ -1318,11 +1318,14 @@ func checkExclusive(ctx *cli.Context, args ...interface{}) {
if i+1 < len(args) {
switch option := args[i+1].(type) {
case string:
// Extended flag, expand the name and shift the arguments
// Extended flag check, make sure value set doesn't conflict with passed in option
if ctx.String(flag.Names()[0]) == option {
name += "=" + option
set = append(set, "--"+name)
}
// shift arguments and continue
i++
continue
case cli.Flag:
default:
@ -1378,10 +1381,10 @@ func SetXDCXConfig(ctx *cli.Context, cfg *XDCx.Config, XDCDataDir string) {
// SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// Avoid conflicting network flags
checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag)
checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag)
checkExclusive(ctx, LightServFlag, LightModeFlag)
checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")
CheckExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag)
CheckExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag)
CheckExclusive(ctx, LightServFlag, LightModeFlag)
CheckExclusive(ctx, LightServFlag, SyncModeFlag, "light")
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
setEtherbase(ctx, ks, cfg)

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Adapted from: https://golang.org/src/crypto/cipher/xor.go
// Adapted from: https://go.dev/src/crypto/subtle/xor_generic.go
// Package bitutil implements fast bitwise operations.
package bitutil

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Adapted from: https://golang.org/src/crypto/cipher/xor_test.go
// Adapted from: https://go.dev/src/crypto/subtle/xor_test.go
package bitutil
@ -190,6 +190,8 @@ func benchmarkBaseOR(b *testing.B, size int) {
}
}
var GloBool bool // Exported global will not be dead-code eliminated, at least not yet.
// Benchmarks the potentially optimized bit testing performance.
func BenchmarkFastTest1KB(b *testing.B) { benchmarkFastTest(b, 1024) }
func BenchmarkFastTest2KB(b *testing.B) { benchmarkFastTest(b, 2048) }
@ -197,9 +199,11 @@ func BenchmarkFastTest4KB(b *testing.B) { benchmarkFastTest(b, 4096) }
func benchmarkFastTest(b *testing.B, size int) {
p := make([]byte, size)
a := false
for i := 0; i < b.N; i++ {
TestBytes(p)
a = a != TestBytes(p)
}
GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
}
// Benchmarks the baseline bit testing performance.
@ -209,7 +213,9 @@ func BenchmarkBaseTest4KB(b *testing.B) { benchmarkBaseTest(b, 4096) }
func benchmarkBaseTest(b *testing.B, size int) {
p := make([]byte, size)
a := false
for i := 0; i < b.N; i++ {
safeTestBytes(p)
a = a != safeTestBytes(p)
}
GloBool = a // Use of benchmark "result" to prevent total dead code elimination.
}

View file

@ -18,6 +18,7 @@ package bitutil
import (
"bytes"
"fmt"
"math/rand"
"testing"
@ -48,19 +49,23 @@ func TestEncodingCycle(t *testing.T) {
"0xdf7070533534333636313639343638373532313536346c1bc333393438373130707063363430353639343638373532313536346c1bc333393438336336346c65fe",
}
for i, tt := range tests {
data := hexutil.MustDecode(tt)
proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
if err != nil {
t.Errorf("test %d: failed to decompress compressed data: %v", i, err)
continue
}
if !bytes.Equal(data, proc) {
t.Errorf("test %d: compress/decompress mismatch: have %x, want %x", i, proc, data)
if err := testEncodingCycle(hexutil.MustDecode(tt)); err != nil {
t.Errorf("test %d: %v", i, err)
}
}
}
func testEncodingCycle(data []byte) error {
proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
if err != nil {
return fmt.Errorf("failed to decompress compressed data: %v", err)
}
if !bytes.Equal(data, proc) {
return fmt.Errorf("compress/decompress mismatch: have %x, want %x", proc, data)
}
return nil
}
// Tests that data bitset decoding and rencoding works and is bijective.
func TestDecodingCycle(t *testing.T) {
tests := []struct {
@ -179,3 +184,41 @@ func benchmarkEncoding(b *testing.B, bytes int, fill float64) {
bitsetDecodeBytes(bitsetEncodeBytes(data), len(data))
}
}
func FuzzEncoder(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
if err := testEncodingCycle(data); err != nil {
t.Fatal(err)
}
})
}
func FuzzDecoder(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
fuzzDecode(data)
})
}
// fuzzDecode implements a go-fuzz fuzzer method to test the bit decoding and
// reencoding algorithm.
func fuzzDecode(data []byte) {
blob, err := DecompressBytes(data, 1024)
if err != nil {
return
}
// re-compress it (it's OK if the re-compressed differs from the
// original - the first input may not have been compressed at all)
comp := CompressBytes(blob)
if len(comp) > len(blob) {
// After compression, it must be smaller or equal
panic("bad compression")
}
// But decompressing it once again should work
decomp, err := DecompressBytes(data, 1024)
if err != nil {
panic(err)
}
if !bytes.Equal(decomp, blob) {
panic("content mismatch")
}
}

View file

@ -17,25 +17,20 @@
// Package common contains various helper functions.
package common
import "encoding/hex"
import (
"encoding/hex"
"errors"
func ToHex(b []byte) string {
hex := Bytes2Hex(b)
// Prefer output of "0x0" instead of "0x"
if len(hex) == 0 {
hex = "0"
}
return "0x" + hex
}
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
)
// FromHex returns the bytes represented by the hexadecimal string s.
// s may be prefixed with "0x".
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
s = s[2:]
}
if (s[0] == 'x' || s[0] == 'X') && (s[1] == 'd' || s[1] == 'D') && (s[2] == 'c' || s[2] == 'C') {
s = s[3:]
}
if has0xPrefix(s) {
s = s[2:]
} else if hasXdcPrefix(s) {
s = s[3:]
}
if len(s)%2 == 1 {
s = "0" + s
@ -43,9 +38,7 @@ func FromHex(s string) []byte {
return Hex2Bytes(s)
}
// Copy bytes
//
// Returns an exact copy of the provided bytes
// CopyBytes returns an exact copy of the provided bytes.
func CopyBytes(b []byte) (copiedBytes []byte) {
if b == nil {
return nil
@ -55,17 +48,23 @@ func CopyBytes(b []byte) (copiedBytes []byte) {
return
}
func hasXDCPrefix(str string) bool {
return len(str) >= 3 && (str[0] == 'x' || str[0] == 'X') && (str[1] == 'd' || str[1] == 'D') && (str[2] == 'c' || str[2] == 'C')
}
func hasHexPrefix(str string) bool {
// has0xPrefix validates str begins with '0x' or '0X'.
func has0xPrefix(str string) bool {
return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')
}
// hasXdcPrefix validates s begins with 'xdc' or 'XDC'.
func hasXdcPrefix(s string) bool {
return len(s) >= 3 && (s[0] == 'x' || s[0] == 'X') && (s[1] == 'd' || s[1] == 'D') && (s[2] == 'c' || s[2] == 'C')
}
// isHexCharacter returns bool of c being a valid hexadecimal.
func isHexCharacter(c byte) bool {
return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')
}
// isHex validates whether each byte is valid hexadecimal string.
func isHex(str string) bool {
if len(str)%2 != 0 {
return false
@ -78,31 +77,41 @@ func isHex(str string) bool {
return true
}
// Bytes2Hex returns the hexadecimal encoding of d.
func Bytes2Hex(d []byte) string {
return hex.EncodeToString(d)
}
// Hex2Bytes returns the bytes represented by the hexadecimal string str.
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
// Hex2BytesFixed returns bytes of a specified fixed length flen.
func Hex2BytesFixed(str string, flen int) []byte {
h, _ := hex.DecodeString(str)
if len(h) == flen {
return h
} else {
if len(h) > flen {
return h[len(h)-flen:]
} else {
hh := make([]byte, flen)
copy(hh[flen-len(h):flen], h[:])
return hh
}
}
if len(h) > flen {
return h[len(h)-flen:]
}
hh := make([]byte, flen)
copy(hh[flen-len(h):flen], h[:])
return hh
}
// ParseHexOrString tries to hexdecode b, but if the prefix is missing, it instead just returns the raw bytes
func ParseHexOrString(str string) ([]byte, error) {
b, err := hexutil.Decode(str)
if errors.Is(err, hexutil.ErrMissingPrefix) {
return []byte(str), nil
}
return b, err
}
// RightPadBytes zero-pads slice to the right up to length l.
func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
@ -114,6 +123,7 @@ func RightPadBytes(slice []byte, l int) []byte {
return padded
}
// LeftPadBytes zero-pads slice to the left up to length l.
func LeftPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
@ -124,3 +134,14 @@ func LeftPadBytes(slice []byte, l int) []byte {
return padded
}
// TrimLeftZeroes returns a subslice of s without leading zeroes
func TrimLeftZeroes(s []byte) []byte {
idx := 0
for ; idx < len(s); idx++ {
if s[idx] != 0 {
break
}
}
return s[idx:]
}

View file

@ -19,41 +19,43 @@ package common
import (
"bytes"
"testing"
checker "gopkg.in/check.v1"
)
type BytesSuite struct{}
func TestCopyBytes(t *testing.T) {
input := []byte{1, 2, 3, 4}
var _ = checker.Suite(&BytesSuite{})
func (s *BytesSuite) TestCopyBytes(c *checker.C) {
data1 := []byte{1, 2, 3, 4}
exp1 := []byte{1, 2, 3, 4}
res1 := CopyBytes(data1)
c.Assert(res1, checker.DeepEquals, exp1)
v := CopyBytes(input)
if !bytes.Equal(v, []byte{1, 2, 3, 4}) {
t.Fatal("not equal after copy")
}
v[0] = 99
if bytes.Equal(v, input) {
t.Fatal("result is not a copy")
}
}
func (s *BytesSuite) TestLeftPadBytes(c *checker.C) {
val1 := []byte{1, 2, 3, 4}
exp1 := []byte{0, 0, 0, 0, 1, 2, 3, 4}
res1 := LeftPadBytes(val1, 8)
res2 := LeftPadBytes(val1, 2)
c.Assert(res1, checker.DeepEquals, exp1)
c.Assert(res2, checker.DeepEquals, val1)
}
func (s *BytesSuite) TestRightPadBytes(c *checker.C) {
func TestLeftPadBytes(t *testing.T) {
val := []byte{1, 2, 3, 4}
exp := []byte{1, 2, 3, 4, 0, 0, 0, 0}
padded := []byte{0, 0, 0, 0, 1, 2, 3, 4}
resstd := RightPadBytes(val, 8)
resshrt := RightPadBytes(val, 2)
if r := LeftPadBytes(val, 8); !bytes.Equal(r, padded) {
t.Fatalf("LeftPadBytes(%v, 8) == %v", val, r)
}
if r := LeftPadBytes(val, 2); !bytes.Equal(r, val) {
t.Fatalf("LeftPadBytes(%v, 2) == %v", val, r)
}
}
c.Assert(resstd, checker.DeepEquals, exp)
c.Assert(resshrt, checker.DeepEquals, val)
func TestRightPadBytes(t *testing.T) {
val := []byte{1, 2, 3, 4}
padded := []byte{1, 2, 3, 4, 0, 0, 0, 0}
if r := RightPadBytes(val, 8); !bytes.Equal(r, padded) {
t.Fatalf("RightPadBytes(%v, 8) == %v", val, r)
}
if r := RightPadBytes(val, 2); !bytes.Equal(r, val) {
t.Fatalf("RightPadBytes(%v, 2) == %v", val, r)
}
}
func TestFromHex(t *testing.T) {

View file

@ -0,0 +1,45 @@
// 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 compiler wraps the Solidity and Vyper compiler executables (solc; vyper).
package compiler
// Contract contains information about a compiled contract, alongside its code and runtime code.
type Contract struct {
Code string `json:"code"`
RuntimeCode string `json:"runtime-code"`
Info ContractInfo `json:"info"`
Hashes map[string]string `json:"hashes"`
}
// ContractInfo contains information about a compiled contract, including access
// to the ABI definition, source mapping, user and developer docs, and metadata.
//
// Depending on the source, language version, compiler version, and compiler
// options will provide information about how the contract was compiled.
type ContractInfo struct {
Source string `json:"source"`
Language string `json:"language"`
LanguageVersion string `json:"languageVersion"`
CompilerVersion string `json:"compilerVersion"`
CompilerOptions string `json:"compilerOptions"`
SrcMap interface{} `json:"srcMap"`
SrcMapRuntime string `json:"srcMapRuntime"`
AbiDefinition interface{} `json:"abiDefinition"`
UserDoc interface{} `json:"userDoc"`
DeveloperDoc interface{} `json:"developerDoc"`
Metadata string `json:"metadata"`
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors
// 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
@ -14,163 +14,81 @@
// 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 compiler wraps the Solidity compiler executable (solc).
// Package compiler wraps the ABI compilation outputs.
package compiler
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
type Contract struct {
Code string `json:"code"`
Info ContractInfo `json:"info"`
}
type ContractInfo struct {
Source string `json:"source"`
Language string `json:"language"`
LanguageVersion string `json:"languageVersion"`
CompilerVersion string `json:"compilerVersion"`
CompilerOptions string `json:"compilerOptions"`
AbiDefinition interface{} `json:"abiDefinition"`
UserDoc interface{} `json:"userDoc"`
DeveloperDoc interface{} `json:"developerDoc"`
Metadata string `json:"metadata"`
}
// Solidity contains information about the solidity compiler.
type Solidity struct {
Path, Version, FullVersion string
Major, Minor, Patch int
}
// --combined-output format
type solcOutput struct {
Contracts map[string]struct {
Bin, Abi, Devdoc, Userdoc, Metadata string
BinRuntime string `json:"bin-runtime"`
SrcMapRuntime string `json:"srcmap-runtime"`
Bin, SrcMap, Abi, Devdoc, Userdoc, Metadata string
Hashes map[string]string
}
Version string
}
func (s *Solidity) makeArgs() []string {
p := []string{
"--combined-json", "bin,abi,userdoc,devdoc",
"--optimize", // code optimizer switched on
// solidity v.0.8 changes the way ABI, Devdoc and Userdoc are serialized
type solcOutputV8 struct {
Contracts map[string]struct {
BinRuntime string `json:"bin-runtime"`
SrcMapRuntime string `json:"srcmap-runtime"`
Bin, SrcMap, Metadata string
Abi interface{}
Devdoc interface{}
Userdoc interface{}
Hashes map[string]string
}
if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
p[1] += ",metadata"
}
return p
Version string
}
// SolidityVersion runs solc and parses its version output.
func SolidityVersion(solc string) (*Solidity, error) {
if solc == "" {
solc = "solc"
}
var out bytes.Buffer
cmd := exec.Command(solc, "--version")
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return nil, err
}
matches := versionRegexp.FindStringSubmatch(out.String())
if len(matches) != 4 {
return nil, fmt.Errorf("can't parse solc version %q", out.String())
}
s := &Solidity{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
if s.Major, err = strconv.Atoi(matches[1]); err != nil {
return nil, err
}
if s.Minor, err = strconv.Atoi(matches[2]); err != nil {
return nil, err
}
if s.Patch, err = strconv.Atoi(matches[3]); err != nil {
return nil, err
}
return s, nil
}
// CompileSolidityString builds and returns all the contracts contained within a source string.
func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
if len(source) == 0 {
return nil, errors.New("solc: empty source string")
}
s, err := SolidityVersion(solc)
if err != nil {
return nil, err
}
args := append(s.makeArgs(), "--")
cmd := exec.Command(s.Path, append(args, "-")...)
cmd.Stdin = strings.NewReader(source)
return s.run(cmd, source)
}
// CompileSolidity compiles all given Solidity source files.
func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
if len(sourcefiles) == 0 {
return nil, errors.New("solc: no source files")
}
source, err := slurpFiles(sourcefiles)
if err != nil {
return nil, err
}
s, err := SolidityVersion(solc)
if err != nil {
return nil, err
}
args := append(s.makeArgs(), "--")
cmd := exec.Command(s.Path, append(args, sourcefiles...)...)
return s.run(cmd, source)
}
func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
var stderr, stdout bytes.Buffer
cmd.Stderr = &stderr
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
}
// ParseCombinedJSON takes the direct output of a solc --combined-output run and
// parses it into a map of string contract name to Contract structs. The
// provided source, language and compiler version, and compiler options are all
// passed through into the Contract structs.
//
// The solc output is expected to contain ABI, source mapping, user docs, and dev docs.
//
// Returns an error if the JSON is malformed or missing data, or if the JSON
// embedded within the JSON is malformed.
func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutput
if err := json.Unmarshal(stdout.Bytes(), &output); err != nil {
return nil, err
if err := json.Unmarshal(combinedJSON, &output); err != nil {
// Try to parse the output with the new solidity v.0.8.0 rules
return parseCombinedJSONV8(combinedJSON, source, languageVersion, compilerVersion, compilerOptions)
}
// Compilation succeeded, assemble and return the contracts.
contracts := make(map[string]*Contract)
for name, info := range output.Contracts {
// Parse the individual compilation results.
var abi interface{}
var abi, userdoc, devdoc interface{}
if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil {
return nil, fmt.Errorf("solc: error reading abi definition (%v)", err)
}
var userdoc interface{}
if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); err != nil {
return nil, fmt.Errorf("solc: error reading user doc: %v", err)
return nil, fmt.Errorf("solc: error reading userdoc definition (%v)", err)
}
var devdoc interface{}
if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); err != nil {
return nil, fmt.Errorf("solc: error reading dev doc: %v", err)
return nil, fmt.Errorf("solc: error reading devdoc definition (%v)", err)
}
contracts[name] = &Contract{
Code: "0x" + info.Bin,
Code: "0x" + info.Bin,
RuntimeCode: "0x" + info.BinRuntime,
Hashes: info.Hashes,
Info: ContractInfo{
Source: source,
Language: "Solidity",
LanguageVersion: s.Version,
CompilerVersion: s.Version,
CompilerOptions: strings.Join(s.makeArgs(), " "),
LanguageVersion: languageVersion,
CompilerVersion: compilerVersion,
CompilerOptions: compilerOptions,
SrcMap: info.SrcMap,
SrcMapRuntime: info.SrcMapRuntime,
AbiDefinition: abi,
UserDoc: userdoc,
DeveloperDoc: devdoc,
@ -181,14 +99,34 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
return contracts, nil
}
func slurpFiles(files []string) (string, error) {
var concat bytes.Buffer
for _, file := range files {
content, err := os.ReadFile(file)
if err != nil {
return "", err
}
concat.Write(content)
// parseCombinedJSONV8 parses the direct output of solc --combined-output
// and parses it using the rules from solidity v.0.8.0 and later.
func parseCombinedJSONV8(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutputV8
if err := json.Unmarshal(combinedJSON, &output); err != nil {
return nil, err
}
return concat.String(), nil
// Compilation succeeded, assemble and return the contracts.
contracts := make(map[string]*Contract)
for name, info := range output.Contracts {
contracts[name] = &Contract{
Code: "0x" + info.Bin,
RuntimeCode: "0x" + info.BinRuntime,
Hashes: info.Hashes,
Info: ContractInfo{
Source: source,
Language: "Solidity",
LanguageVersion: languageVersion,
CompilerVersion: compilerVersion,
CompilerOptions: compilerOptions,
SrcMap: info.SrcMap,
SrcMapRuntime: info.SrcMapRuntime,
AbiDefinition: info.Abi,
UserDoc: info.Userdoc,
DeveloperDoc: info.Devdoc,
Metadata: info.Metadata,
},
}
}
return contracts, nil
}

View file

@ -1,78 +0,0 @@
// Copyright 2015 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 compiler
import (
"os/exec"
"testing"
)
const (
testSource = `
contract test {
/// @notice Will multiply ` + "`a`" + ` by 7.
function multiply(uint a) returns(uint d) {
return a * 7;
}
}
`
)
func skipWithoutSolc(t *testing.T) {
if _, err := exec.LookPath("solc"); err != nil {
t.Skip(err)
}
}
func TestCompiler(t *testing.T) {
t.SkipNow()
skipWithoutSolc(t)
contracts, err := CompileSolidityString("", testSource)
if err != nil {
t.Fatalf("error compiling source. result %v: %v", contracts, err)
}
if len(contracts) != 1 {
t.Errorf("one contract expected, got %d", len(contracts))
}
c, ok := contracts["test"]
if !ok {
c, ok = contracts["<stdin>:test"]
if !ok {
t.Fatal("info for contract 'test' not present in result")
}
}
if c.Code == "" {
t.Error("empty code")
}
if c.Info.Source != testSource {
t.Error("wrong source")
}
if c.Info.CompilerVersion == "" {
t.Error("empty version")
}
}
func TestCompileError(t *testing.T) {
skipWithoutSolc(t)
contracts, err := CompileSolidityString("", testSource[4:])
if err == nil {
t.Errorf("error expected compiling source. got none. result %v", contracts)
}
t.Logf("error: %v", err)
}

View file

@ -37,8 +37,8 @@ func Report(extra ...interface{}) {
fmt.Fprintln(os.Stderr, "#### BUG! PLEASE REPORT ####")
}
// PrintDepricationWarning prinst the given string in a box using fmt.Println.
func PrintDepricationWarning(str string) {
// PrintDeprecationWarning prints the given string in a box using fmt.Println.
func PrintDeprecationWarning(str string) {
line := strings.Repeat("#", len(str)+4)
emptyLine := strings.Repeat(" ", len(str))
fmt.Printf(`

View file

@ -17,7 +17,6 @@
package common
import (
"fmt"
"regexp"
"strings"
"time"
@ -27,12 +26,12 @@ import (
// the unnecessary precision off from the formatted textual representation.
type PrettyDuration time.Duration
var prettyDurationRe = regexp.MustCompile(`\.[0-9]+`)
var prettyDurationRe = regexp.MustCompile(`\.[0-9]{4,}`)
// String implements the Stringer interface, allowing pretty printing of duration
// values rounded to three decimals.
func (d PrettyDuration) String() string {
label := fmt.Sprintf("%v", time.Duration(d))
label := time.Duration(d).String()
if match := prettyDurationRe.FindString(label); len(match) > 4 {
label = strings.Replace(label, match, match[:4], 1)
}

View file

@ -18,7 +18,7 @@
Package hexutil implements hex encoding with 0x prefix.
This encoding is used by the Ethereum RPC API to transport binary data in JSON payloads.
Encoding Rules
# Encoding Rules
All hex data must have prefix "0x".
@ -175,13 +175,14 @@ func MustDecodeBig(input string) *big.Int {
}
// EncodeBig encodes bigint as a hex string with 0x prefix.
// The sign of the integer is ignored.
func EncodeBig(bigint *big.Int) string {
nbits := bigint.BitLen()
if nbits == 0 {
if sign := bigint.Sign(); sign == 0 {
return "0x0"
} else if sign > 0 {
return "0x" + bigint.Text(16)
} else {
return "-0x" + bigint.Text(16)[1:]
}
return fmt.Sprintf("%#x", bigint)
}
func has0xPrefix(input string) bool {

View file

@ -201,3 +201,15 @@ func TestDecodeUint64(t *testing.T) {
}
}
}
func BenchmarkEncodeBig(b *testing.B) {
for _, bench := range encodeBigTests {
b.Run(bench.want, func(b *testing.B) {
b.ReportAllocs()
bigint := bench.input.(*big.Int)
for i := 0; i < b.N; i++ {
EncodeBig(bigint)
}
})
}
}

View file

@ -23,6 +23,8 @@ import (
"math/big"
"reflect"
"strconv"
"github.com/holiman/uint256"
)
var (
@ -30,6 +32,7 @@ var (
bigT = reflect.TypeOf((*Big)(nil))
uintT = reflect.TypeOf(Uint(0))
uint64T = reflect.TypeOf(Uint64(0))
u256T = reflect.TypeOf((*uint256.Int)(nil))
)
// Bytes marshals/unmarshals as a JSON string with 0x prefix.
@ -195,6 +198,48 @@ func (b *Big) String() string {
return EncodeBig(b.ToInt())
}
// U256 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type U256 uint256.Int
// MarshalText implements encoding.TextMarshaler
func (b U256) MarshalText() ([]byte, error) {
u256 := (*uint256.Int)(&b)
return []byte(u256.Hex()), nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (b *U256) UnmarshalJSON(input []byte) error {
// The uint256.Int.UnmarshalJSON method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
if !isString(input) {
return errNonString(u256T)
}
// The hex decoder needs to accept empty string ("") as '0', which uint256.Int
// would reject.
if len(input) == 2 {
(*uint256.Int)(b).Clear()
return nil
}
err := (*uint256.Int)(b).SetFromHex(string(input[1 : len(input)-1]))
if err != nil {
return &json.UnmarshalTypeError{Value: err.Error(), Type: u256T}
}
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler
func (b *U256) UnmarshalText(input []byte) error {
// The uint256.Int.UnmarshalText method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
return (*uint256.Int)(b).SetFromHex(string(input))
}
// String returns the hex encoding of b.
func (b *U256) String() string {
return (*uint256.Int)(b).Hex()
}
// Uint64 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type Uint64 uint64

View file

@ -23,6 +23,8 @@ import (
"errors"
"math/big"
"testing"
"github.com/holiman/uint256"
)
func checkError(t *testing.T, input string, got, want error) bool {
@ -88,7 +90,7 @@ func TestUnmarshalBytes(t *testing.T) {
if !checkError(t, test.input, err, test.wantErr) {
continue
}
if !bytes.Equal(test.want.([]byte), []byte(v)) {
if !bytes.Equal(test.want.([]byte), v) {
t.Errorf("input %s: value mismatch: got %x, want %x", test.input, &v, test.want)
continue
}
@ -176,6 +178,64 @@ func TestUnmarshalBig(t *testing.T) {
}
}
var unmarshalU256Tests = []unmarshalTest{
// invalid encoding
{input: "", wantErr: errJSONEOF},
{input: "null", wantErr: errNonString(u256T)},
{input: "10", wantErr: errNonString(u256T)},
{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, u256T)},
{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, u256T)},
{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, u256T)},
{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{
input: `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
wantErr: wrapTypeError(ErrBig256Range, u256T),
},
// valid encoding
{input: `""`, want: big.NewInt(0)},
{input: `"0x0"`, want: big.NewInt(0)},
{input: `"0x2"`, want: big.NewInt(0x2)},
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
{input: `"0X2F2"`, want: big.NewInt(0x2f2)},
{input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
{input: `"0xbBb"`, want: big.NewInt(0xbbb)},
{input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
{
input: `"0x112233445566778899aabbccddeeff"`,
want: referenceBig("112233445566778899aabbccddeeff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
},
}
func TestUnmarshalU256(t *testing.T) {
for _, test := range unmarshalU256Tests {
var v U256
err := json.Unmarshal([]byte(test.input), &v)
if !checkError(t, test.input, err, test.wantErr) {
continue
}
if test.want == nil {
continue
}
want := new(uint256.Int)
want.SetFromBig(test.want.(*big.Int))
have := (*uint256.Int)(&v)
if want.Cmp(have) != 0 {
t.Errorf("input %s: value mismatch: have %x, want %x", test.input, have, want)
continue
}
}
}
func BenchmarkUnmarshalBig(b *testing.B) {
input := []byte(`"0x123456789abcdef123456789abcdef"`)
for i := 0; i < b.N; i++ {

View file

@ -23,12 +23,9 @@ import (
)
var (
tt255 = BigPow(2, 255)
tt256 = BigPow(2, 256)
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
MaxBig256 = new(big.Int).Set(tt256m1)
tt63 = BigPow(2, 63)
MaxBig63 = new(big.Int).Sub(tt63, big.NewInt(1))
)
const (
@ -41,6 +38,24 @@ const (
// HexOrDecimal256 marshals big.Int as hex or decimal.
type HexOrDecimal256 big.Int
// NewHexOrDecimal256 creates a new HexOrDecimal256
func NewHexOrDecimal256(x int64) *HexOrDecimal256 {
b := big.NewInt(x)
h := HexOrDecimal256(*b)
return &h
}
// UnmarshalJSON implements json.Unmarshaler.
//
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
// quoted decimal strings.
func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error {
if len(input) > 1 && input[0] == '"' {
input = input[1 : len(input)-1]
}
return i.UnmarshalText(input)
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
bigint, ok := ParseBig256(string(input))
@ -78,7 +93,7 @@ func ParseBig256(s string) (*big.Int, bool) {
return bigint, ok
}
// MustParseBig parses s as a 256 bit big integer and panics if the string is invalid.
// MustParseBig256 parses s as a 256 bit big integer and panics if the string is invalid.
func MustParseBig256(s string) *big.Int {
v, ok := ParseBig256(s)
if !ok {
@ -93,32 +108,6 @@ func BigPow(a, b int64) *big.Int {
return r.Exp(r, big.NewInt(b), nil)
}
// BigMax returns the larger of x or y.
func BigMax(x, y *big.Int) *big.Int {
if x.Cmp(y) < 0 {
return y
}
return x
}
// BigMin returns the smaller of x or y.
func BigMin(x, y *big.Int) *big.Int {
if x.Cmp(y) > 0 {
return y
}
return x
}
// FirstBitSet returns the index of the first 1 bit in v, counting from LSB.
func FirstBitSet(v *big.Int) int {
for i := 0; i < v.BitLen(); i++ {
if v.Bit(i) > 0 {
return i
}
}
return v.BitLen()
}
// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
// of the slice is at least n bytes.
func PaddedBigBytes(bigint *big.Int, n int) []byte {
@ -130,34 +119,6 @@ func PaddedBigBytes(bigint *big.Int, n int) []byte {
return ret
}
// bigEndianByteAt returns the byte at position n,
// in Big-Endian encoding
// So n==0 returns the least significant byte
func bigEndianByteAt(bigint *big.Int, n int) byte {
words := bigint.Bits()
// Check word-bucket the byte will reside in
i := n / wordBytes
if i >= len(words) {
return byte(0)
}
word := words[i]
// Offset of the byte
shift := 8 * uint(n%wordBytes)
return byte(word >> shift)
}
// Byte returns the byte at position n,
// with the supplied padlength in Little-Endian encoding.
// n==0 returns the MSB
// Example: bigint '5', padlength 32, n=31 => 5
func Byte(bigint *big.Int, padlength, n int) byte {
if n >= padlength {
return byte(0)
}
return bigEndianByteAt(bigint, padlength-1-n)
}
// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
// that buf has enough space. If buf is too short the result will be incomplete.
func ReadBits(bigint *big.Int, buf []byte) {
@ -171,42 +132,13 @@ func ReadBits(bigint *big.Int, buf []byte) {
}
}
// U256 encodes as a 256 bit two's complement number. This operation is destructive.
// U256 encodes x as a 256 bit two's complement number. This operation is destructive.
func U256(x *big.Int) *big.Int {
return x.And(x, tt256m1)
}
// S256 interprets x as a two's complement number.
// x must not exceed 256 bits (the result is undefined if it does) and is not modified.
//
// S256(0) = 0
// S256(1) = 1
// S256(2**255) = -2**255
// S256(2**256-1) = -1
func S256(x *big.Int) *big.Int {
if x.Cmp(tt255) < 0 {
return x
} else {
return new(big.Int).Sub(x, tt256)
}
}
// Exp implements exponentiation by squaring.
// Exp returns a newly-allocated big integer and does not change
// base or exponent. The result is truncated to 256 bits.
//
// Courtesy @karalabe and @chfast
func Exp(base, exponent *big.Int) *big.Int {
result := big.NewInt(1)
for _, word := range exponent.Bits() {
for i := 0; i < wordBits; i++ {
if word&1 == 1 {
U256(result.Mul(result, base))
}
U256(base.Mul(base, base))
word >>= 1
}
}
return result
// U256Bytes converts a big Int into a 256bit EVM number.
// This operation is destructive.
func U256Bytes(n *big.Int) []byte {
return PaddedBigBytes(U256(n), 32)
}

View file

@ -21,8 +21,6 @@ import (
"encoding/hex"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
)
func TestHexOrDecimal256(t *testing.T) {
@ -70,53 +68,6 @@ func TestMustParseBig256(t *testing.T) {
MustParseBig256("ggg")
}
func TestBigMax(t *testing.T) {
a := big.NewInt(10)
b := big.NewInt(5)
max1 := BigMax(a, b)
if max1 != a {
t.Errorf("Expected %d got %d", a, max1)
}
max2 := BigMax(b, a)
if max2 != a {
t.Errorf("Expected %d got %d", a, max2)
}
}
func TestBigMin(t *testing.T) {
a := big.NewInt(10)
b := big.NewInt(5)
min1 := BigMin(a, b)
if min1 != b {
t.Errorf("Expected %d got %d", b, min1)
}
min2 := BigMin(b, a)
if min2 != b {
t.Errorf("Expected %d got %d", b, min2)
}
}
func TestFirstBigSet(t *testing.T) {
tests := []struct {
num *big.Int
ix int
}{
{big.NewInt(0), 0},
{big.NewInt(1), 0},
{big.NewInt(2), 1},
{big.NewInt(0x100), 8},
}
for _, test := range tests {
if ix := FirstBitSet(test.num); ix != test.ix {
t.Errorf("FirstBitSet(b%b) = %d, want %d", test.num, ix, test.ix)
}
}
}
func TestPaddedBigBytes(t *testing.T) {
tests := []struct {
num *big.Int
@ -156,22 +107,7 @@ func BenchmarkPaddedBigBytesSmallOnePadding(b *testing.B) {
}
}
func BenchmarkByteAtBrandNew(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ {
bigEndianByteAt(bigint, 15)
}
}
func BenchmarkByteAt(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ {
bigEndianByteAt(bigint, 15)
}
}
func BenchmarkByteAtOld(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ {
PaddedBigBytes(bigint, 32)
@ -181,9 +117,9 @@ func BenchmarkByteAtOld(b *testing.B) {
func TestReadBits(t *testing.T) {
check := func(input string) {
want, _ := hex.DecodeString(input)
int, _ := new(big.Int).SetString(input, 16)
n, _ := new(big.Int).SetString(input, 16)
buf := make([]byte, len(want))
ReadBits(int, buf)
ReadBits(n, buf)
if !bytes.Equal(buf, want) {
t.Errorf("have: %x\nwant: %x", buf, want)
}
@ -212,106 +148,12 @@ func TestU256(t *testing.T) {
}
}
func TestBigEndianByteAt(t *testing.T) {
tests := []struct {
x string
y int
exp byte
}{
{"00", 0, 0x00},
{"01", 1, 0x00},
{"00", 1, 0x00},
{"01", 0, 0x01},
{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x30},
{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x20},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0xAB},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 500, 0x00},
}
for _, test := range tests {
v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
actual := bigEndianByteAt(v, test.y)
if actual != test.exp {
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
}
func TestU256Bytes(t *testing.T) {
ubytes := make([]byte, 32)
ubytes[31] = 1
}
}
func TestLittleEndianByteAt(t *testing.T) {
tests := []struct {
x string
y int
exp byte
}{
{"00", 0, 0x00},
{"01", 1, 0x00},
{"00", 1, 0x00},
{"01", 0, 0x00},
{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x00},
{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 0, 0xAB},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 1, 0xCD},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 0, 0x00},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 1, 0xCD},
{"0000000000000000000000000000000000000000000000000000000000102030", 31, 0x30},
{"0000000000000000000000000000000000000000000000000000000000102030", 30, 0x20},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32, 0x0},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 31, 0xFF},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0xFFFF, 0x0},
}
for _, test := range tests {
v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
actual := Byte(v, 32, test.y)
if actual != test.exp {
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
}
}
}
func TestS256(t *testing.T) {
tests := []struct{ x, y *big.Int }{
{x: big.NewInt(0), y: big.NewInt(0)},
{x: big.NewInt(1), y: big.NewInt(1)},
{x: big.NewInt(2), y: big.NewInt(2)},
{
x: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
y: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
},
{
x: BigPow(2, 255),
y: new(big.Int).Neg(BigPow(2, 255)),
},
{
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1)),
y: big.NewInt(-1),
},
{
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2)),
y: big.NewInt(-2),
},
}
for _, test := range tests {
if y := S256(test.x); y.Cmp(test.y) != 0 {
t.Errorf("S256(%x) = %x, want %x", test.x, y, test.y)
}
}
}
func TestExp(t *testing.T) {
tests := []struct{ base, exponent, result *big.Int }{
{base: big.NewInt(0), exponent: big.NewInt(0), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
}
for _, test := range tests {
if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
t.Errorf("Exp(%d, %d) = %d, want %d", test.base, test.exponent, result, test.result)
}
unsigned := U256Bytes(big.NewInt(1))
if !bytes.Equal(unsigned, ubytes) {
t.Errorf("expected %x got %x", ubytes, unsigned)
}
}

View file

@ -18,35 +18,31 @@ package math
import (
"fmt"
"math/bits"
"strconv"
)
const (
// Integer limit values.
MaxInt8 = 1<<7 - 1
MinInt8 = -1 << 7
MaxInt16 = 1<<15 - 1
MinInt16 = -1 << 15
MaxInt32 = 1<<31 - 1
MinInt32 = -1 << 31
MaxInt64 = 1<<63 - 1
MinInt64 = -1 << 63
MaxUint8 = 1<<8 - 1
MaxUint16 = 1<<16 - 1
MaxUint32 = 1<<32 - 1
MaxUint64 = 1<<64 - 1
)
// HexOrDecimal64 marshals uint64 as hex or decimal.
type HexOrDecimal64 uint64
// UnmarshalJSON implements json.Unmarshaler.
//
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
// quoted decimal strings.
func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error {
if len(input) > 1 && input[0] == '"' {
input = input[1 : len(input)-1]
}
return i.UnmarshalText(input)
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
int, ok := ParseUint64(string(input))
n, ok := ParseUint64(string(input))
if !ok {
return fmt.Errorf("invalid hex or decimal integer %q", input)
}
*i = HexOrDecimal64(int)
*i = HexOrDecimal64(n)
return nil
}
@ -78,22 +74,20 @@ func MustParseUint64(s string) uint64 {
return v
}
// NOTE: The following methods need to be optimised using either bit checking or asm
// SafeSub returns subtraction result and whether overflow occurred.
// SafeSub returns x-y and checks for overflow.
func SafeSub(x, y uint64) (uint64, bool) {
return x - y, x < y
diff, borrowOut := bits.Sub64(x, y, 0)
return diff, borrowOut != 0
}
// SafeAdd returns the result and whether overflow occurred.
// SafeAdd returns x+y and checks for overflow.
func SafeAdd(x, y uint64) (uint64, bool) {
return x + y, y > MaxUint64-x
sum, carryOut := bits.Add64(x, y, 0)
return sum, carryOut != 0
}
// SafeMul returns multiplication result and whether overflow occurred.
// SafeMul returns x*y and checks for overflow.
func SafeMul(x, y uint64) (uint64, bool) {
if x == 0 || y == 0 {
return 0, false
}
return x * y, y > MaxUint64/x
hi, lo := bits.Mul64(x, y)
return lo, hi != 0
}

View file

@ -17,6 +17,7 @@
package math
import (
"math"
"testing"
)
@ -36,8 +37,8 @@ func TestOverflow(t *testing.T) {
op operation
}{
// add operations
{MaxUint64, 1, true, add},
{MaxUint64 - 1, 1, false, add},
{math.MaxUint64, 1, true, add},
{math.MaxUint64 - 1, 1, false, add},
// sub operations
{0, 1, true, sub},
@ -46,8 +47,8 @@ func TestOverflow(t *testing.T) {
// mul operations
{0, 0, false, mul},
{10, 10, false, mul},
{MaxUint64, 2, true, mul},
{MaxUint64, 1, false, mul},
{math.MaxUint64, 2, true, mul},
{math.MaxUint64, 1, false, mul},
} {
var overflows bool
switch test.op {

View file

@ -20,15 +20,19 @@ package mclock
import (
"time"
"github.com/aristanetworks/goarista/monotime"
_ "unsafe" // for go:linkname
)
//go:noescape
//go:linkname nanotime runtime.nanotime
func nanotime() int64
// AbsTime represents absolute monotonic time.
type AbsTime time.Duration
type AbsTime int64
// Now returns the current absolute monotonic time.
func Now() AbsTime {
return AbsTime(monotime.Now())
return AbsTime(nanotime())
}
// Add returns t + d as absolute time.
@ -74,7 +78,7 @@ type System struct{}
// Now returns the current monotonic time.
func (c System) Now() AbsTime {
return AbsTime(monotime.Now())
return Now()
}
// Sleep blocks for the given duration.

1
common/mclock/mclock.s Normal file
View file

@ -0,0 +1 @@
// This file exists in order to be able to use go:linkname.

View file

@ -58,7 +58,7 @@ func (s *Simulated) Run(d time.Duration) {
s.mu.Lock()
s.init()
end := s.now + AbsTime(d)
end := s.now.Add(d)
var do []func()
for len(s.scheduled) > 0 && s.scheduled[0].at <= end {
ev := heap.Pop(&s.scheduled).(*simTimer)
@ -134,7 +134,7 @@ func (s *Simulated) AfterFunc(d time.Duration, fn func()) Timer {
func (s *Simulated) schedule(d time.Duration, fn func()) *simTimer {
s.init()
at := s.now + AbsTime(d)
at := s.now.Add(d)
ev := &simTimer{do: fn, at: at, s: s}
heap.Push(&s.scheduled, ev)
s.cond.Broadcast()

View file

@ -34,13 +34,12 @@ func limitUnsigned256(x *Number) *Number {
func limitSigned256(x *Number) *Number {
if x.num.Cmp(tt255) < 0 {
return x
} else {
x.num.Sub(x.num, tt256)
return x
}
x.num.Sub(x.num, tt256)
return x
}
// Number function
// Initialiser is a Number function
type Initialiser func(n int64) *Number
// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
@ -58,58 +57,58 @@ func NewInitialiser(limiter func(*Number) *Number) Initialiser {
}
}
// Return a Number with a UNSIGNED limiter up to 256 bits
// Uint256 returns a Number with a UNSIGNED limiter up to 256 bits
func Uint256(n int64) *Number {
return &Number{big.NewInt(n), limitUnsigned256}
}
// Return a Number with a SIGNED limiter up to 256 bits
// Int256 returns Number with a SIGNED limiter up to 256 bits
func Int256(n int64) *Number {
return &Number{big.NewInt(n), limitSigned256}
}
// Returns a Number with a SIGNED unlimited size
// Big returns a Number with a SIGNED unlimited size
func Big(n int64) *Number {
return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
}
// Sets i to sum of x+y
// Add sets i to sum of x+y
func (i *Number) Add(x, y *Number) *Number {
i.num.Add(x.num, y.num)
return i.limit(i)
}
// Sets i to difference of x-y
// Sub sets i to difference of x-y
func (i *Number) Sub(x, y *Number) *Number {
i.num.Sub(x.num, y.num)
return i.limit(i)
}
// Sets i to product of x*y
// Mul sets i to product of x*y
func (i *Number) Mul(x, y *Number) *Number {
i.num.Mul(x.num, y.num)
return i.limit(i)
}
// Sets i to the quotient prodject of x/y
// Div sets i to the quotient prodject of x/y
func (i *Number) Div(x, y *Number) *Number {
i.num.Div(x.num, y.num)
return i.limit(i)
}
// Sets i to x % y
// Mod sets i to x % y
func (i *Number) Mod(x, y *Number) *Number {
i.num.Mod(x.num, y.num)
return i.limit(i)
}
// Sets i to x << s
// Lsh sets i to x << s
func (i *Number) Lsh(x *Number, s uint) *Number {
i.num.Lsh(x.num, s)
return i.limit(i)
}
// Sets i to x^y
// Pow sets i to x^y
func (i *Number) Pow(x, y *Number) *Number {
i.num.Exp(x.num, y.num, big.NewInt(0))
return i.limit(i)
@ -117,13 +116,13 @@ func (i *Number) Pow(x, y *Number) *Number {
// Setters
// Set x to i
// Set sets x to i
func (i *Number) Set(x *Number) *Number {
i.num.Set(x.num)
return i.limit(i)
}
// Set x bytes to i
// SetBytes sets x bytes to i
func (i *Number) SetBytes(x []byte) *Number {
i.num.SetBytes(x)
return i.limit(i)
@ -131,21 +130,21 @@ func (i *Number) SetBytes(x []byte) *Number {
// Cmp compares x and y and returns:
//
// -1 if x < y
// 0 if x == y
// +1 if x > y
// -1 if x < y
// 0 if x == y
// +1 if x > y
func (i *Number) Cmp(x *Number) int {
return i.num.Cmp(x.num)
}
// Getters
// Returns the string representation of i
// String returns the string representation of i
func (i *Number) String() string {
return i.num.String()
}
// Returns the byte representation of i
// Bytes returns the byte representation of i
func (i *Number) Bytes() []byte {
return i.num.Bytes()
}
@ -160,17 +159,17 @@ func (i *Number) Int64() int64 {
return i.num.Int64()
}
// Returns the signed version of i
// Int256 returns the signed version of i
func (i *Number) Int256() *Number {
return Int(0).Set(i)
}
// Returns the unsigned version of i
// Uint256 returns the unsigned version of i
func (i *Number) Uint256() *Number {
return Uint(0).Set(i)
}
// Returns the index of the first bit that's set to 1
// FirstBitSet returns the index of the first bit that's set to 1
func (i *Number) FirstBitSet() int {
for j := 0; j < i.num.BitLen(); j++ {
if i.num.Bit(j) > 0 {

View file

@ -17,19 +17,11 @@
package common
import (
"fmt"
"os"
"path/filepath"
"runtime"
)
// MakeName creates a node name that follows the ethereum convention
// for such names. It adds the operation system name and Go runtime version
// the name.
func MakeName(name, version string) string {
return fmt.Sprintf("%s/v%s/%s/%s", name, version, runtime.GOOS, runtime.Version())
}
// FileExist checks if a file exists at filePath.
func FileExist(filePath string) bool {
_, err := os.Stat(filePath)
if err != nil && os.IsNotExist(err) {
@ -39,9 +31,10 @@ func FileExist(filePath string) bool {
return true
}
func AbsolutePath(Datadir string, filename string) string {
// AbsolutePath returns datadir + filename, or filename if it is absolute.
func AbsolutePath(datadir string, filename string) string {
if filepath.IsAbs(filename) {
return filename
}
return filepath.Join(Datadir, filename)
return filepath.Join(datadir, filename)
}

View file

@ -17,6 +17,7 @@
package prque
import (
"cmp"
"container/heap"
"time"
@ -26,79 +27,94 @@ import (
// LazyQueue is a priority queue data structure where priorities can change over
// time and are only evaluated on demand.
// Two callbacks are required:
// - priority evaluates the actual priority of an item
// - maxPriority gives an upper estimate for the priority in any moment between
// now and the given absolute time
// - priority evaluates the actual priority of an item
// - maxPriority gives an upper estimate for the priority in any moment between
// now and the given absolute time
//
// If the upper estimate is exceeded then Update should be called for that item.
// A global Refresh function should also be called periodically.
type LazyQueue struct {
type LazyQueue[P cmp.Ordered, V any] struct {
clock mclock.Clock
// Items are stored in one of two internal queues ordered by estimated max
// priority until the next and the next-after-next refresh. Update and Refresh
// always places items in queue[1].
queue [2]*sstack
popQueue *sstack
period time.Duration
maxUntil mclock.AbsTime
indexOffset int
setIndex SetIndexCallback
priority PriorityCallback
maxPriority MaxPriorityCallback
queue [2]*sstack[P, V]
popQueue *sstack[P, V]
period time.Duration
maxUntil mclock.AbsTime
indexOffset int
setIndex SetIndexCallback[V]
priority PriorityCallback[P, V]
maxPriority MaxPriorityCallback[P, V]
lastRefresh1, lastRefresh2 mclock.AbsTime
}
type (
PriorityCallback func(data interface{}, now mclock.AbsTime) int64 // actual priority callback
MaxPriorityCallback func(data interface{}, until mclock.AbsTime) int64 // estimated maximum priority callback
PriorityCallback[P cmp.Ordered, V any] func(data V) P // actual priority callback
MaxPriorityCallback[P cmp.Ordered, V any] func(data V, until mclock.AbsTime) P // estimated maximum priority callback
)
// NewLazyQueue creates a new lazy queue
func NewLazyQueue(setIndex SetIndexCallback, priority PriorityCallback, maxPriority MaxPriorityCallback, clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue {
q := &LazyQueue{
popQueue: newSstack(nil),
setIndex: setIndex,
priority: priority,
maxPriority: maxPriority,
clock: clock,
period: refreshPeriod}
func NewLazyQueue[P cmp.Ordered, V any](setIndex SetIndexCallback[V], priority PriorityCallback[P, V], maxPriority MaxPriorityCallback[P, V], clock mclock.Clock, refreshPeriod time.Duration) *LazyQueue[P, V] {
q := &LazyQueue[P, V]{
popQueue: newSstack[P, V](nil),
setIndex: setIndex,
priority: priority,
maxPriority: maxPriority,
clock: clock,
period: refreshPeriod,
lastRefresh1: clock.Now(),
lastRefresh2: clock.Now(),
}
q.Reset()
q.Refresh()
q.refresh(clock.Now())
return q
}
// Reset clears the contents of the queue
func (q *LazyQueue) Reset() {
q.queue[0] = newSstack(q.setIndex0)
q.queue[1] = newSstack(q.setIndex1)
func (q *LazyQueue[P, V]) Reset() {
q.queue[0] = newSstack[P, V](q.setIndex0)
q.queue[1] = newSstack[P, V](q.setIndex1)
}
// Refresh should be called at least with the frequency specified by the refreshPeriod parameter
func (q *LazyQueue) Refresh() {
q.maxUntil = q.clock.Now() + mclock.AbsTime(q.period)
// Refresh performs queue re-evaluation if necessary
func (q *LazyQueue[P, V]) Refresh() {
now := q.clock.Now()
for time.Duration(now-q.lastRefresh2) >= q.period*2 {
q.refresh(now)
q.lastRefresh2 = q.lastRefresh1
q.lastRefresh1 = now
}
}
// refresh re-evaluates items in the older queue and swaps the two queues
func (q *LazyQueue[P, V]) refresh(now mclock.AbsTime) {
q.maxUntil = now.Add(q.period)
for q.queue[0].Len() != 0 {
q.Push(heap.Pop(q.queue[0]).(*item).value)
q.Push(heap.Pop(q.queue[0]).(*item[P, V]).value)
}
q.queue[0], q.queue[1] = q.queue[1], q.queue[0]
q.indexOffset = 1 - q.indexOffset
q.maxUntil += mclock.AbsTime(q.period)
q.maxUntil = q.maxUntil.Add(q.period)
}
// Push adds an item to the queue
func (q *LazyQueue) Push(data interface{}) {
heap.Push(q.queue[1], &item{data, q.maxPriority(data, q.maxUntil)})
func (q *LazyQueue[P, V]) Push(data V) {
heap.Push(q.queue[1], &item[P, V]{data, q.maxPriority(data, q.maxUntil)})
}
// Update updates the upper priority estimate for the item with the given queue index
func (q *LazyQueue) Update(index int) {
func (q *LazyQueue[P, V]) Update(index int) {
q.Push(q.Remove(index))
}
// Pop removes and returns the item with the greatest actual priority
func (q *LazyQueue) Pop() (interface{}, int64) {
func (q *LazyQueue[P, V]) Pop() (V, P) {
var (
resData interface{}
resPri int64
resData V
resPri P
)
q.MultiPop(func(data interface{}, priority int64) bool {
q.MultiPop(func(data V, priority P) bool {
resData = data
resPri = priority
return false
@ -108,7 +124,7 @@ func (q *LazyQueue) Pop() (interface{}, int64) {
// peekIndex returns the index of the internal queue where the item with the
// highest estimated priority is or -1 if both are empty
func (q *LazyQueue) peekIndex() int {
func (q *LazyQueue[P, V]) peekIndex() int {
if q.queue[0].Len() != 0 {
if q.queue[1].Len() != 0 && q.queue[1].blocks[0][0].priority > q.queue[0].blocks[0][0].priority {
return 1
@ -124,51 +140,48 @@ func (q *LazyQueue) peekIndex() int {
// MultiPop pops multiple items from the queue and is more efficient than calling
// Pop multiple times. Popped items are passed to the callback. MultiPop returns
// when the callback returns false or there are no more items to pop.
func (q *LazyQueue) MultiPop(callback func(data interface{}, priority int64) bool) {
now := q.clock.Now()
func (q *LazyQueue[P, V]) MultiPop(callback func(data V, priority P) bool) {
nextIndex := q.peekIndex()
for nextIndex != -1 {
data := heap.Pop(q.queue[nextIndex]).(*item).value
heap.Push(q.popQueue, &item{data, q.priority(data, now)})
data := heap.Pop(q.queue[nextIndex]).(*item[P, V]).value
heap.Push(q.popQueue, &item[P, V]{data, q.priority(data)})
nextIndex = q.peekIndex()
for q.popQueue.Len() != 0 && (nextIndex == -1 || q.queue[nextIndex].blocks[0][0].priority < q.popQueue.blocks[0][0].priority) {
i := heap.Pop(q.popQueue).(*item)
i := heap.Pop(q.popQueue).(*item[P, V])
if !callback(i.value, i.priority) {
for q.popQueue.Len() != 0 {
q.Push(heap.Pop(q.popQueue).(*item).value)
q.Push(heap.Pop(q.popQueue).(*item[P, V]).value)
}
return
}
nextIndex = q.peekIndex() // re-check because callback is allowed to push items back
}
}
}
// PopItem pops the item from the queue only, dropping the associated priority value.
func (q *LazyQueue) PopItem() interface{} {
func (q *LazyQueue[P, V]) PopItem() V {
i, _ := q.Pop()
return i
}
// Remove removes removes the item with the given index.
func (q *LazyQueue) Remove(index int) interface{} {
if index < 0 {
return nil
}
return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item).value
// Remove removes the item with the given index.
func (q *LazyQueue[P, V]) Remove(index int) V {
return heap.Remove(q.queue[index&1^q.indexOffset], index>>1).(*item[P, V]).value
}
// Empty checks whether the priority queue is empty.
func (q *LazyQueue) Empty() bool {
func (q *LazyQueue[P, V]) Empty() bool {
return q.queue[0].Len() == 0 && q.queue[1].Len() == 0
}
// Size returns the number of items in the priority queue.
func (q *LazyQueue) Size() int {
func (q *LazyQueue[P, V]) Size() int {
return q.queue[0].Len() + q.queue[1].Len()
}
// setIndex0 translates internal queue item index to the virtual index space of LazyQueue
func (q *LazyQueue) setIndex0(data interface{}, index int) {
func (q *LazyQueue[P, V]) setIndex0(data V, index int) {
if index == -1 {
q.setIndex(data, -1)
} else {
@ -177,6 +190,6 @@ func (q *LazyQueue) setIndex0(data interface{}, index int) {
}
// setIndex1 translates internal queue item index to the virtual index space of LazyQueue
func (q *LazyQueue) setIndex1(data interface{}, index int) {
func (q *LazyQueue[P, V]) setIndex1(data V, index int) {
q.setIndex(data, index+index+1)
}

View file

@ -40,7 +40,7 @@ type lazyItem struct {
index int
}
func testPriority(a interface{}, now mclock.AbsTime) int64 {
func testPriority(a interface{}) int64 {
return a.(*lazyItem).p
}
@ -56,7 +56,6 @@ func testSetIndex(a interface{}, i int) {
}
func TestLazyQueue(t *testing.T) {
rand.Seed(time.Now().UnixNano())
clock := &mclock.Simulated{}
q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh)

View file

@ -18,61 +18,59 @@
package prque
import (
"cmp"
"container/heap"
)
// Priority queue data structure.
type Prque struct {
cont *sstack
// Prque is a priority queue data structure.
type Prque[P cmp.Ordered, V any] struct {
cont *sstack[P, V]
}
// New creates a new priority queue.
func New(setIndex SetIndexCallback) *Prque {
return &Prque{newSstack(setIndex)}
func New[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *Prque[P, V] {
return &Prque[P, V]{newSstack[P, V](setIndex)}
}
// Pushes a value with a given priority into the queue, expanding if necessary.
func (p *Prque) Push(data interface{}, priority int64) {
heap.Push(p.cont, &item{data, priority})
// Push a value with a given priority into the queue, expanding if necessary.
func (p *Prque[P, V]) Push(data V, priority P) {
heap.Push(p.cont, &item[P, V]{data, priority})
}
// Peek returns the value with the greates priority but does not pop it off.
func (p *Prque) Peek() (interface{}, int64) {
// Peek returns the value with the greatest priority but does not pop it off.
func (p *Prque[P, V]) Peek() (V, P) {
item := p.cont.blocks[0][0]
return item.value, item.priority
}
// Pops the value with the greates priority off the stack and returns it.
// Pop the value with the greatest priority off the stack and returns it.
// Currently no shrinking is done.
func (p *Prque) Pop() (interface{}, int64) {
item := heap.Pop(p.cont).(*item)
func (p *Prque[P, V]) Pop() (V, P) {
item := heap.Pop(p.cont).(*item[P, V])
return item.value, item.priority
}
// Pops only the item from the queue, dropping the associated priority value.
func (p *Prque) PopItem() interface{} {
return heap.Pop(p.cont).(*item).value
// PopItem pops only the item from the queue, dropping the associated priority value.
func (p *Prque[P, V]) PopItem() V {
return heap.Pop(p.cont).(*item[P, V]).value
}
// Remove removes the element with the given index.
func (p *Prque) Remove(i int) interface{} {
if i < 0 {
return nil
}
return heap.Remove(p.cont, i)
func (p *Prque[P, V]) Remove(i int) V {
return heap.Remove(p.cont, i).(*item[P, V]).value
}
// Checks whether the priority queue is empty.
func (p *Prque) Empty() bool {
// Empty checks whether the priority queue is empty.
func (p *Prque[P, V]) Empty() bool {
return p.cont.Len() == 0
}
// Returns the number of element in the priority queue.
func (p *Prque) Size() int {
// Size returns the number of element in the priority queue.
func (p *Prque[P, V]) Size() int {
return p.cont.Len()
}
// Clears the contents of the priority queue.
func (p *Prque) Reset() {
*p = *New(p.cont.setIndex)
// Reset clears the contents of the priority queue.
func (p *Prque[P, V]) Reset() {
*p = *New[P, V](p.cont.setIndex)
}

133
common/prque/prque_test.go Normal file
View file

@ -0,0 +1,133 @@
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: use of this source code is governed by a BSD
// license that can be found in the LICENSE file. Alternatively, the CookieJar
// toolbox may be used in accordance with the terms and conditions contained
// in a signed written agreement between you and the author(s).
package prque
import (
"math/rand"
"testing"
)
func TestPrque(t *testing.T) {
// Generate a batch of random data and a specific priority order
size := 16 * blockSize
prio := rand.Perm(size)
data := make([]int, size)
for i := 0; i < size; i++ {
data[i] = rand.Int()
}
queue := New[int, int](nil)
for rep := 0; rep < 2; rep++ {
// Fill a priority queue with the above data
for i := 0; i < size; i++ {
queue.Push(data[i], prio[i])
if queue.Size() != i+1 {
t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1)
}
}
// Create a map the values to the priorities for easier verification
dict := make(map[int]int)
for i := 0; i < size; i++ {
dict[prio[i]] = data[i]
}
// Pop out the elements in priority order and verify them
prevPrio := size + 1
for !queue.Empty() {
val, prio := queue.Pop()
if prio > prevPrio {
t.Errorf("invalid priority order: %v after %v.", prio, prevPrio)
}
prevPrio = prio
if val != dict[prio] {
t.Errorf("push/pop mismatch: have %v, want %v.", val, dict[prio])
}
delete(dict, prio)
}
}
}
func TestReset(t *testing.T) {
// Generate a batch of random data and a specific priority order
size := 16 * blockSize
prio := rand.Perm(size)
data := make([]int, size)
for i := 0; i < size; i++ {
data[i] = rand.Int()
}
queue := New[int, int](nil)
for rep := 0; rep < 2; rep++ {
// Fill a priority queue with the above data
for i := 0; i < size; i++ {
queue.Push(data[i], prio[i])
if queue.Size() != i+1 {
t.Errorf("queue size mismatch: have %v, want %v.", queue.Size(), i+1)
}
}
// Create a map the values to the priorities for easier verification
dict := make(map[int]int)
for i := 0; i < size; i++ {
dict[prio[i]] = data[i]
}
// Pop out half the elements in priority order and verify them
prevPrio := size + 1
for i := 0; i < size/2; i++ {
val, prio := queue.Pop()
if prio > prevPrio {
t.Errorf("invalid priority order: %v after %v.", prio, prevPrio)
}
prevPrio = prio
if val != dict[prio] {
t.Errorf("push/pop mismatch: have %v, want %v.", val, dict[prio])
}
delete(dict, prio)
}
// Reset and ensure it's empty
queue.Reset()
if !queue.Empty() {
t.Errorf("priority queue not empty after reset: %v", queue)
}
}
}
func BenchmarkPush(b *testing.B) {
// Create some initial data
data := make([]int, b.N)
prio := make([]int64, b.N)
for i := 0; i < len(data); i++ {
data[i] = rand.Int()
prio[i] = rand.Int63()
}
// Execute the benchmark
b.ResetTimer()
queue := New[int64, int](nil)
for i := 0; i < len(data); i++ {
queue.Push(data[i], prio[i])
}
}
func BenchmarkPop(b *testing.B) {
// Create some initial data
data := make([]int, b.N)
prio := make([]int64, b.N)
for i := 0; i < len(data); i++ {
data[i] = rand.Int()
prio[i] = rand.Int63()
}
queue := New[int64, int](nil)
for i := 0; i < len(data); i++ {
queue.Push(data[i], prio[i])
}
// Execute the benchmark
b.ResetTimer()
for !queue.Empty() {
queue.Pop()
}
}

View file

@ -10,51 +10,50 @@
package prque
import "cmp"
// The size of a block of data
const blockSize = 4096
// A prioritized item in the sorted stack.
//
// Note: priorities can "wrap around" the int64 range, a comes before b if (a.priority - b.priority) > 0.
// The difference between the lowest and highest priorities in the queue at any point should be less than 2^63.
type item struct {
value interface{}
priority int64
type item[P cmp.Ordered, V any] struct {
value V
priority P
}
// SetIndexCallback is called when the element is moved to a new index.
// Providing SetIndexCallback is optional, it is needed only if the application needs
// to delete elements other than the top one.
type SetIndexCallback func(data interface{}, index int)
type SetIndexCallback[V any] func(data V, index int)
// Internal sortable stack data structure. Implements the Push and Pop ops for
// the stack (heap) functionality and the Len, Less and Swap methods for the
// sortability requirements of the heaps.
type sstack struct {
setIndex SetIndexCallback
type sstack[P cmp.Ordered, V any] struct {
setIndex SetIndexCallback[V]
size int
capacity int
offset int
blocks [][]*item
active []*item
blocks [][]*item[P, V]
active []*item[P, V]
}
// Creates a new, empty stack.
func newSstack(setIndex SetIndexCallback) *sstack {
result := new(sstack)
func newSstack[P cmp.Ordered, V any](setIndex SetIndexCallback[V]) *sstack[P, V] {
result := new(sstack[P, V])
result.setIndex = setIndex
result.active = make([]*item, blockSize)
result.blocks = [][]*item{result.active}
result.active = make([]*item[P, V], blockSize)
result.blocks = [][]*item[P, V]{result.active}
result.capacity = blockSize
return result
}
// Pushes a value onto the stack, expanding it if necessary. Required by
// Push a value onto the stack, expanding it if necessary. Required by
// heap.Interface.
func (s *sstack) Push(data interface{}) {
func (s *sstack[P, V]) Push(data any) {
if s.size == s.capacity {
s.active = make([]*item, blockSize)
s.active = make([]*item[P, V], blockSize)
s.blocks = append(s.blocks, s.active)
s.capacity += blockSize
s.offset = 0
@ -63,16 +62,16 @@ func (s *sstack) Push(data interface{}) {
s.offset = 0
}
if s.setIndex != nil {
s.setIndex(data.(*item).value, s.size)
s.setIndex(data.(*item[P, V]).value, s.size)
}
s.active[s.offset] = data.(*item)
s.active[s.offset] = data.(*item[P, V])
s.offset++
s.size++
}
// Pops a value off the stack and returns it. Currently no shrinking is done.
// Pop a value off the stack and returns it. Currently no shrinking is done.
// Required by heap.Interface.
func (s *sstack) Pop() (res interface{}) {
func (s *sstack[P, V]) Pop() (res any) {
s.size--
s.offset--
if s.offset < 0 {
@ -81,24 +80,24 @@ func (s *sstack) Pop() (res interface{}) {
}
res, s.active[s.offset] = s.active[s.offset], nil
if s.setIndex != nil {
s.setIndex(res.(*item).value, -1)
s.setIndex(res.(*item[P, V]).value, -1)
}
return
}
// Returns the length of the stack. Required by sort.Interface.
func (s *sstack) Len() int {
// Len returns the length of the stack. Required by sort.Interface.
func (s *sstack[P, V]) Len() int {
return s.size
}
// Compares the priority of two elements of the stack (higher is first).
// Less compares the priority of two elements of the stack (higher is first).
// Required by sort.Interface.
func (s *sstack) Less(i, j int) bool {
return (s.blocks[i/blockSize][i%blockSize].priority - s.blocks[j/blockSize][j%blockSize].priority) > 0
func (s *sstack[P, V]) Less(i, j int) bool {
return s.blocks[i/blockSize][i%blockSize].priority > s.blocks[j/blockSize][j%blockSize].priority
}
// Swaps two elements in the stack. Required by sort.Interface.
func (s *sstack) Swap(i, j int) {
// Swap two elements in the stack. Required by sort.Interface.
func (s *sstack[P, V]) Swap(i, j int) {
ib, io, jb, jo := i/blockSize, i%blockSize, j/blockSize, j%blockSize
a, b := s.blocks[jb][jo], s.blocks[ib][io]
if s.setIndex != nil {
@ -108,7 +107,7 @@ func (s *sstack) Swap(i, j int) {
s.blocks[ib][io], s.blocks[jb][jo] = a, b
}
// Resets the stack, effectively clearing its contents.
func (s *sstack) Reset() {
*s = *newSstack(s.setIndex)
// Reset the stack, effectively clearing its contents.
func (s *sstack[P, V]) Reset() {
*s = *newSstack[P, V](s.setIndex)
}

100
common/prque/sstack_test.go Normal file
View file

@ -0,0 +1,100 @@
// CookieJar - A contestant's algorithm toolbox
// Copyright (c) 2013 Peter Szilagyi. All rights reserved.
//
// CookieJar is dual licensed: use of this source code is governed by a BSD
// license that can be found in the LICENSE file. Alternatively, the CookieJar
// toolbox may be used in accordance with the terms and conditions contained
// in a signed written agreement between you and the author(s).
package prque
import (
"math/rand"
"sort"
"testing"
)
func TestSstack(t *testing.T) {
// Create some initial data
size := 16 * blockSize
data := make([]*item[int64, int], size)
for i := 0; i < size; i++ {
data[i] = &item[int64, int]{rand.Int(), rand.Int63()}
}
stack := newSstack[int64, int](nil)
for rep := 0; rep < 2; rep++ {
// Push all the data into the stack, pop out every second
secs := []*item[int64, int]{}
for i := 0; i < size; i++ {
stack.Push(data[i])
if i%2 == 0 {
secs = append(secs, stack.Pop().(*item[int64, int]))
}
}
rest := []*item[int64, int]{}
for stack.Len() > 0 {
rest = append(rest, stack.Pop().(*item[int64, int]))
}
// Make sure the contents of the resulting slices are ok
for i := 0; i < size; i++ {
if i%2 == 0 && data[i] != secs[i/2] {
t.Errorf("push/pop mismatch: have %v, want %v.", secs[i/2], data[i])
}
if i%2 == 1 && data[i] != rest[len(rest)-i/2-1] {
t.Errorf("push/pop mismatch: have %v, want %v.", rest[len(rest)-i/2-1], data[i])
}
}
}
}
func TestSstackSort(t *testing.T) {
// Create some initial data
size := 16 * blockSize
data := make([]*item[int64, int], size)
for i := 0; i < size; i++ {
data[i] = &item[int64, int]{rand.Int(), int64(i)}
}
// Push all the data into the stack
stack := newSstack[int64, int](nil)
for _, val := range data {
stack.Push(val)
}
// Sort and pop the stack contents (should reverse the order)
sort.Sort(stack)
for _, val := range data {
out := stack.Pop()
if out != val {
t.Errorf("push/pop mismatch after sort: have %v, want %v.", out, val)
}
}
}
func TestSstackReset(t *testing.T) {
// Create some initial data
size := 16 * blockSize
data := make([]*item[int64, int], size)
for i := 0; i < size; i++ {
data[i] = &item[int64, int]{rand.Int(), rand.Int63()}
}
stack := newSstack[int64, int](nil)
for rep := 0; rep < 2; rep++ {
// Push all the data into the stack, pop out every second
secs := []*item[int64, int]{}
for i := 0; i < size; i++ {
stack.Push(data[i])
if i%2 == 0 {
secs = append(secs, stack.Pop().(*item[int64, int]))
}
}
// Reset and verify both pulled and stack contents
stack.Reset()
if stack.Len() != 0 {
t.Errorf("stack not empty after reset: %v", stack)
}
for i := 0; i < size; i++ {
if i%2 == 0 && data[i] != secs[i/2] {
t.Errorf("push/pop mismatch: have %v, want %v.", secs[i/2], data[i])
}
}
}
}

View file

@ -26,10 +26,14 @@ type StorageSize float64
// String implements the stringer interface.
func (s StorageSize) String() string {
if s > 1000000 {
return fmt.Sprintf("%.2f mB", s/1000000)
} else if s > 1000 {
return fmt.Sprintf("%.2f kB", s/1000)
if s > 1099511627776 {
return fmt.Sprintf("%.2f TiB", s/1099511627776)
} else if s > 1073741824 {
return fmt.Sprintf("%.2f GiB", s/1073741824)
} else if s > 1048576 {
return fmt.Sprintf("%.2f MiB", s/1048576)
} else if s > 1024 {
return fmt.Sprintf("%.2f KiB", s/1024)
} else {
return fmt.Sprintf("%.2f B", s)
}
@ -38,10 +42,14 @@ func (s StorageSize) String() string {
// TerminalString implements log.TerminalStringer, formatting a string for console
// output during logging.
func (s StorageSize) TerminalString() string {
if s > 1000000 {
return fmt.Sprintf("%.2fmB", s/1000000)
} else if s > 1000 {
return fmt.Sprintf("%.2fkB", s/1000)
if s > 1099511627776 {
return fmt.Sprintf("%.2fTiB", s/1099511627776)
} else if s > 1073741824 {
return fmt.Sprintf("%.2fGiB", s/1073741824)
} else if s > 1048576 {
return fmt.Sprintf("%.2fMiB", s/1048576)
} else if s > 1024 {
return fmt.Sprintf("%.2fKiB", s/1024)
} else {
return fmt.Sprintf("%.2fB", s)
}

View file

@ -25,8 +25,10 @@ func TestStorageSizeString(t *testing.T) {
size StorageSize
str string
}{
{2381273, "2.38 mB"},
{2192, "2.19 kB"},
{2839274474874, "2.58 TiB"},
{2458492810, "2.29 GiB"},
{2381273, "2.27 MiB"},
{2192, "2.14 KiB"},
{12, "12.00 B"},
}
@ -36,3 +38,22 @@ func TestStorageSizeString(t *testing.T) {
}
}
}
func TestStorageSizeTerminalString(t *testing.T) {
tests := []struct {
size StorageSize
str string
}{
{2839274474874, "2.58TiB"},
{2458492810, "2.29GiB"},
{2381273, "2.27MiB"},
{2192, "2.14KiB"},
{12, "12.00B"},
}
for _, test := range tests {
if test.size.TerminalString() != test.str {
t.Errorf("%f: got %q, want %q", float64(test.size), test.size.TerminalString(), test.str)
}
}
}

View file

@ -19,10 +19,12 @@ package common
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"math/rand"
"reflect"
"strconv"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"golang.org/x/crypto/sha3"
@ -52,6 +54,9 @@ const (
)
var (
// MaxHash represents the maximum possible hash value.
MaxHash = HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
BlockSignersBinary = Address{19: 0x89} // xdc0000000000000000000000000000000000000089
MasternodeVotingSMCBinary = Address{19: 0x88} // xdc0000000000000000000000000000000000000088
RandomizeSMCBinary = Address{19: 0x90} // xdc0000000000000000000000000000000000000090
@ -106,7 +111,7 @@ func (h Hash) Cmp(other Hash) int {
// IsZero returns if a Hash is empty
func (h Hash) IsZero() bool { return h == Hash{} }
// Get the string representation of the underlying hash
// Str get the string representation of the underlying hash
func (h Hash) Str() string { return string(h[:]) }
// Bytes gets the byte representation of the underlying hash.
@ -130,10 +135,34 @@ func (h Hash) String() string {
return h.Hex()
}
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
// without going through the stringer interface used for logging.
// Format implements fmt.Formatter.
// Hash supports the %v, %s, %q, %x, %X and %d format verbs.
func (h Hash) Format(s fmt.State, c rune) {
fmt.Fprintf(s, "%"+string(c), h[:])
hexb := make([]byte, 2+len(h)*2)
copy(hexb, "0x")
hex.Encode(hexb[2:], h[:])
switch c {
case 'x', 'X':
if !s.Flag('#') {
hexb = hexb[2:]
}
if c == 'X' {
hexb = bytes.ToUpper(hexb)
}
fallthrough
case 'v', 's':
s.Write(hexb)
case 'q':
q := []byte{'"'}
s.Write(q)
s.Write(hexb)
s.Write(q)
case 'd':
fmt.Fprint(s, ([len(h)]byte)(h))
default:
fmt.Fprintf(s, "%%!%c(hash=%x)", c, h)
}
}
// UnmarshalText parses a hash in hex syntax.
@ -161,14 +190,6 @@ func (h *Hash) SetBytes(b []byte) {
copy(h[HashLength-len(b):], b)
}
// Set string `s` to h. If s is larger than len(h) s will be cropped (from left) to fit.
func (h *Hash) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *Hash) Set(other Hash) {
copy(h[:], other[:])
}
// Generate implements testing/quick.Generator.
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
m := rand.Intn(len(h))
@ -178,10 +199,6 @@ func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.ValueOf(h)
}
func EmptyHash(h Hash) bool {
return h == Hash{}
}
// UnprefixedHash allows marshaling a Hash without 0x prefix.
type UnprefixedHash Hash
@ -200,6 +217,8 @@ func (h UnprefixedHash) MarshalText() ([]byte, error) {
// Address represents the 20 byte address of an Ethereum account.
type Address [AddressLength]byte
// BytesToAddress returns Address with value b.
// If b is larger than len(h), b will be cropped from the left.
func BytesToAddress(b []byte) Address {
var a Address
a.SetBytes(b)
@ -219,11 +238,10 @@ func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) }
// IsHexAddress verifies whether a string can represent a valid hex-encoded
// Ethereum address or not.
func IsHexAddress(s string) bool {
if hasXDCPrefix(s) {
s = s[3:]
}
if hasHexPrefix(s) {
if has0xPrefix(s) {
s = s[2:]
} else if hasXdcPrefix(s) {
s = s[3:]
}
return len(s) == 2*AddressLength && isHex(s)
}
@ -231,46 +249,87 @@ func IsHexAddress(s string) bool {
// IsZero returns if a address is empty
func (a Address) IsZero() bool { return a == Address{} }
// Get the string representation of the underlying address
func (a Address) Str() string { return string(a[:]) }
// Str gets the string representation of the underlying address
func (a Address) Str() string { return string(a[:]) }
// Bytes gets the string representation of the underlying address.
func (a Address) Bytes() []byte { return a[:] }
// Hash converts an address to a hash by left-padding it with zeros.
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
// Big converts an address to a big integer.
func (a Address) Big() *big.Int { return new(big.Int).SetBytes(a[:]) }
func (a Address) Hash() Hash { return BytesToHash(a[:]) }
// Hex returns an EIP55-compliant hex string representation of the address.
func (a Address) Hex() string {
unchecksummed := hex.EncodeToString(a[:])
sha := sha3.NewLegacyKeccak256()
sha.Write([]byte(unchecksummed))
hash := sha.Sum(nil)
checksumed := a.checksumHex()
return "xdc" + string(checksumed[2:])
}
result := []byte(unchecksummed)
for i := 0; i < len(result); i++ {
hashByte := hash[i/2]
// String implements fmt.Stringer.
func (a Address) String() string {
return a.Hex()
}
func (a *Address) checksumHex() []byte {
buf := a.hex()
// compute checksum
sha := sha3.NewLegacyKeccak256()
sha.Write(buf[2:])
hash := sha.Sum(nil)
for i := 2; i < len(buf); i++ {
hashByte := hash[(i-2)/2]
if i%2 == 0 {
hashByte = hashByte >> 4
} else {
hashByte &= 0xf
}
if result[i] > '9' && hashByte > 7 {
result[i] -= 32
if buf[i] > '9' && hashByte > 7 {
buf[i] -= 32
}
}
return "xdc" + string(result)
return buf[:]
}
// String implements the stringer interface and is used also by the logger.
func (a Address) String() string {
return a.Hex()
func (a Address) hex() []byte {
var buf [len(a)*2 + 2]byte
copy(buf[:2], "0x")
hex.Encode(buf[2:], a[:])
return buf[:]
}
// Format implements fmt.Formatter, forcing the byte slice to be formatted as is,
// without going through the stringer interface used for logging.
// Format implements fmt.Formatter.
// Address supports the %v, %s, %q, %x, %X and %d format verbs.
func (a Address) Format(s fmt.State, c rune) {
fmt.Fprintf(s, "%"+string(c), a[:])
switch c {
case 'v', 's':
s.Write(a.checksumHex())
case 'q':
q := []byte{'"'}
s.Write(q)
s.Write(a.checksumHex())
s.Write(q)
case 'x', 'X':
// %x disables the checksum.
hex := a.hex()
if !s.Flag('#') {
hex = hex[2:]
}
if c == 'X' {
hex = bytes.ToUpper(hex)
}
s.Write(hex)
case 'd':
fmt.Fprint(s, ([len(a)]byte)(a))
default:
fmt.Fprintf(s, "%%!%c(address=%x)", c, a)
}
}
// Sets the address to the value of b. If b is larger than len(a) it will panic
// SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func (a *Address) SetBytes(b []byte) {
if len(b) > len(a) {
b = b[len(b)-AddressLength:]
@ -278,14 +337,6 @@ func (a *Address) SetBytes(b []byte) {
copy(a[AddressLength-len(b):], b)
}
// Set string `s` to a. If s is larger than len(a) it will panic
func (a *Address) SetString(s string) { a.SetBytes([]byte(s)) }
// Sets a to other
func (a *Address) Set(other Address) {
copy(a[:], other[:])
}
// MarshalText returns the hex representation of a.
func (a Address) MarshalText() ([]byte, error) {
// Handle '0x' or 'xdc' prefix here.
@ -306,7 +357,7 @@ func (a *Address) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(addressT, input, a[:])
}
// UnprefixedHash allows marshaling an Address without 0x prefix.
// UnprefixedAddress allows marshaling an Address without 0x prefix.
type UnprefixedAddress Address
// UnmarshalText decodes the address from hex. The 0x prefix is optional.
@ -319,7 +370,7 @@ func (a UnprefixedAddress) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(a[:])), nil
}
// Extract validators from byte array.
// RemoveItemFromArray extracts validators from byte array.
func RemoveItemFromArray(array []Address, items []Address) []Address {
// Create newArray to stop append change array value
newArray := make([]Address, len(array))
@ -340,7 +391,7 @@ func RemoveItemFromArray(array []Address, items []Address) []Address {
return newArray
}
// Extract validators from byte array.
// ExtractAddressToBytes extracts validators from byte array.
func ExtractAddressToBytes(penalties []Address) []byte {
data := []byte{}
for _, signer := range penalties {
@ -359,3 +410,35 @@ func ExtractAddressFromBytes(bytePenalties []byte) []Address {
}
return penalties
}
// AddressEIP55 is an alias of Address with a customized json marshaller
type AddressEIP55 Address
// String returns the hex representation of the address in the manner of EIP55.
func (addr AddressEIP55) String() string {
return Address(addr).Hex()
}
// MarshalJSON marshals the address in the manner of EIP55.
func (addr AddressEIP55) MarshalJSON() ([]byte, error) {
return json.Marshal(addr.String())
}
type Decimal uint64
func isString(input []byte) bool {
return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"'
}
// UnmarshalJSON parses a hash in hex syntax.
func (d *Decimal) UnmarshalJSON(input []byte) error {
if !isString(input) {
return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))}
}
if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil {
*d = Decimal(i)
return nil
} else {
return err
}
}

View file

@ -1,64 +0,0 @@
// Copyright 2015 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/>.
// +build none
//sed -e 's/_N_/Hash/g' -e 's/_S_/32/g' -e '1d' types_template.go | gofmt -w hash.go
package common
import "math/big"
type _N_ [_S_]byte
func BytesTo_N_(b []byte) _N_ {
var h _N_
h.SetBytes(b)
return h
}
func StringTo_N_(s string) _N_ { return BytesTo_N_([]byte(s)) }
func BigTo_N_(b *big.Int) _N_ { return BytesTo_N_(b.Bytes()) }
func HexTo_N_(s string) _N_ { return BytesTo_N_(FromHex(s)) }
// Don't use the default 'String' method in case we want to overwrite
// Get the string representation of the underlying hash
func (h _N_) Str() string { return string(h[:]) }
func (h _N_) Bytes() []byte { return h[:] }
func (h _N_) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
func (h _N_) Hex() string { return "0x" + Bytes2Hex(h[:]) }
// Sets the hash to the value of b. If b is larger than len(h) it will panic
func (h *_N_) SetBytes(b []byte) {
// Use the right most bytes
if len(b) > len(h) {
b = b[len(b)-_S_:]
}
// Reverse the loop
for i := len(b) - 1; i >= 0; i-- {
h[_S_-len(b)+i] = b[i]
}
}
// Set string `s` to h. If s is larger than len(h) it will panic
func (h *_N_) SetString(s string) { h.SetBytes([]byte(s)) }
// Sets h to other
func (h *_N_) Set(other _N_) {
for i, v := range other {
h[i] = v
}
}

View file

@ -17,7 +17,10 @@
package common
import (
"bytes"
"encoding/json"
"fmt"
"math"
"math/big"
"strings"
"testing"
@ -118,8 +121,8 @@ func TestAddressUnmarshalJSON(t *testing.T) {
if test.ShouldErr {
t.Errorf("test #%d: expected error, got none", i)
}
if v.Big().Cmp(test.Output) != 0 {
t.Errorf("test #%d: address mismatch: have %v, want %v", i, v.Big(), test.Output)
if got := new(big.Int).SetBytes(v.Bytes()); got.Cmp(test.Output) != 0 {
t.Errorf("test #%d: address mismatch: have %v, want %v", i, got, test.Output)
}
}
}
@ -156,6 +159,170 @@ func BenchmarkAddressHex(b *testing.B) {
}
}
func TestAddress_Format(t *testing.T) {
b := []byte{
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
}
var addr Address
addr.SetBytes(b)
tests := []struct {
name string
out string
want string
}{
{
name: "println",
out: fmt.Sprintln(addr),
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15\n",
},
{
name: "print",
out: fmt.Sprint(addr),
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
},
{
name: "printf-s",
out: func() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s", addr)
return buf.String()
}(),
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
},
{
name: "printf-q",
out: fmt.Sprintf("%q", addr),
want: `"0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15"`,
},
{
name: "printf-x",
out: fmt.Sprintf("%x", addr),
want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15",
},
{
name: "printf-X",
out: fmt.Sprintf("%X", addr),
want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15",
},
{
name: "printf-#x",
out: fmt.Sprintf("%#x", addr),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15",
},
{
name: "printf-v",
out: fmt.Sprintf("%v", addr),
want: "0xB26f2b342AAb24BCF63ea218c6A9274D30Ab9A15",
},
// The original default formatter for byte slice
{
name: "printf-d",
out: fmt.Sprintf("%d", addr),
want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21]",
},
// Invalid format char.
{
name: "printf-t",
out: fmt.Sprintf("%t", addr),
want: "%!t(address=b26f2b342aab24bcf63ea218c6a9274d30ab9a15)",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.out != tt.want {
t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
}
})
}
}
func TestHash_Format(t *testing.T) {
var hash Hash
hash.SetBytes([]byte{
0xb2, 0x6f, 0x2b, 0x34, 0x2a, 0xab, 0x24, 0xbc, 0xf6, 0x3e,
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
0xa2, 0x18, 0xc6, 0xa9, 0x27, 0x4d, 0x30, 0xab, 0x9a, 0x15,
0x10, 0x00,
})
tests := []struct {
name string
out string
want string
}{
{
name: "println",
out: fmt.Sprintln(hash),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000\n",
},
{
name: "print",
out: fmt.Sprint(hash),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
},
{
name: "printf-s",
out: func() string {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s", hash)
return buf.String()
}(),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
},
{
name: "printf-q",
out: fmt.Sprintf("%q", hash),
want: `"0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000"`,
},
{
name: "printf-x",
out: fmt.Sprintf("%x", hash),
want: "b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
},
{
name: "printf-X",
out: fmt.Sprintf("%X", hash),
want: "B26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
},
{
name: "printf-#x",
out: fmt.Sprintf("%#x", hash),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
},
{
name: "printf-#X",
out: fmt.Sprintf("%#X", hash),
want: "0XB26F2B342AAB24BCF63EA218C6A9274D30AB9A15A218C6A9274D30AB9A151000",
},
{
name: "printf-v",
out: fmt.Sprintf("%v", hash),
want: "0xb26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000",
},
// The original default formatter for byte slice
{
name: "printf-d",
out: fmt.Sprintf("%d", hash),
want: "[178 111 43 52 42 171 36 188 246 62 162 24 198 169 39 77 48 171 154 21 162 24 198 169 39 77 48 171 154 21 16 0]",
},
// Invalid format char.
{
name: "printf-t",
out: fmt.Sprintf("%t", hash),
want: "%!t(hash=b26f2b342aab24bcf63ea218c6a9274d30ab9a15a218c6a9274d30ab9a151000)",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.out != tt.want {
t.Errorf("%s does not render as expected:\n got %s\nwant %s", tt.name, tt.out, tt.want)
}
})
}
}
func TestRemoveItemInArray(t *testing.T) {
array := []Address{HexToAddress("0x0000003"), HexToAddress("0x0000001"), HexToAddress("0x0000002"), HexToAddress("0x0000003")}
remove := []Address{HexToAddress("0x0000002"), HexToAddress("0x0000004"), HexToAddress("0x0000003")}
@ -205,6 +372,30 @@ func TestStringToBinaryAddress(t *testing.T) {
}
}
func TestAddressEIP55(t *testing.T) {
addr := HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
addrEIP55 := AddressEIP55(addr)
if addr.Hex() != addrEIP55.String() {
t.Fatal("AddressEIP55 should match original address hex")
}
blob, err := addrEIP55.MarshalJSON()
if err != nil {
t.Fatal("Failed to marshal AddressEIP55", err)
}
if strings.Trim(string(blob), "\"") != addr.Hex() {
t.Fatal("Address with checksum is expected")
}
var dec Address
if err := json.Unmarshal(blob, &dec); err != nil {
t.Fatal("Failed to unmarshal AddressEIP55", err)
}
if addr != dec {
t.Fatal("Unexpected address after unmarshal")
}
}
func BenchmarkPrettyDuration(b *testing.B) {
var x = PrettyDuration(time.Duration(int64(1203123912312)))
b.Logf("Pre %s", time.Duration(x).String())
@ -215,3 +406,29 @@ func BenchmarkPrettyDuration(b *testing.B) {
}
b.Logf("Post %s", a)
}
func TestDecimalUnmarshalJSON(t *testing.T) {
// These should error
for _, tc := range []string{``, `"`, `""`, `"-1"`} {
if err := new(Decimal).UnmarshalJSON([]byte(tc)); err == nil {
t.Errorf("input %s should cause error", tc)
}
}
// These should succeed
for _, tc := range []struct {
input string
want uint64
}{
{`"0"`, 0},
{`"9223372036854775807"`, math.MaxInt64},
{`"18446744073709551615"`, math.MaxUint64},
} {
have := new(Decimal)
if err := have.UnmarshalJSON([]byte(tc.input)); err != nil {
t.Errorf("input %q triggered error: %v", tc.input, err)
}
if uint64(*have) != tc.want {
t.Errorf("input %q, have %d want %d", tc.input, *have, tc.want)
}
}
}

View file

@ -6,6 +6,7 @@ import (
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/misc"
@ -171,7 +172,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
for index, mn := range masterNodes {
log.Error("[verifyHeader] masternode list during validator verification", "Masternode Address", mn.Hex(), "index", index)
}
log.Error("[verifyHeader] Error while verifying header validator signature", "BlockNumber", header.Number, "Hash", header.Hash().Hex(), "validator in hex", common.ToHex(header.Validator))
log.Error("[verifyHeader] Error while verifying header validator signature", "BlockNumber", header.Number, "Hash", header.Hash().Hex(), "validator in hex", hexutil.Encode(header.Validator))
return err
}
if !verified {

View file

@ -26,7 +26,7 @@ type TradingService interface {
GetEmptyTradingState() (*tradingstate.TradingStateDB, error)
HasTradingState(block *types.Block, author common.Address) bool
GetStateCache() tradingstate.Database
GetTriegc() *prque.Prque
GetTriegc() *prque.Prque[int64, common.Hash]
ApplyOrder(header *types.Header, coinbase common.Address, chain consensus.ChainContext, statedb *state.StateDB, XDCXstatedb *tradingstate.TradingStateDB, orderBook common.Hash, order *tradingstate.OrderItem) ([]map[string]string, []*tradingstate.OrderItem, error)
UpdateMediumPriceBeforeEpoch(epochNumber uint64, tradingStateDB *tradingstate.TradingStateDB, statedb *state.StateDB) error
IsSDKNode() bool
@ -40,7 +40,7 @@ type LendingService interface {
GetLendingState(block *types.Block, author common.Address) (*lendingstate.LendingStateDB, error)
HasLendingState(block *types.Block, author common.Address) bool
GetStateCache() lendingstate.Database
GetTriegc() *prque.Prque
GetTriegc() *prque.Prque[int64, common.Hash]
ApplyOrder(header *types.Header, coinbase common.Address, chain consensus.ChainContext, statedb *state.StateDB, lendingStateDB *lendingstate.LendingStateDB, tradingStateDb *tradingstate.TradingStateDB, lendingOrderBook common.Hash, order *lendingstate.LendingItem) ([]*lendingstate.LendingTrade, []*lendingstate.LendingItem, error)
GetCollateralPrices(header *types.Header, chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, collateralToken common.Address, lendingToken common.Address) (*big.Int, *big.Int, error)
GetMediumTradePriceBeforeEpoch(chain consensus.ChainContext, statedb *state.StateDB, tradingStateDb *tradingstate.TradingStateDB, baseToken common.Address, quoteToken common.Address) (*big.Int, error)

View file

@ -458,7 +458,9 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
expDiff := periodCount.Sub(periodCount, big2)
expDiff.Exp(big2, expDiff, nil)
diff.Add(diff, expDiff)
diff = math.BigMax(diff, params.MinimumDifficulty)
if diff.Cmp(params.MinimumDifficulty) < 0 {
diff = params.MinimumDifficulty
}
}
return diff
}

View file

@ -18,14 +18,14 @@ package blocksigner
import (
"context"
"math/big"
"math/rand"
"testing"
"time"
"math/rand"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
@ -50,7 +50,7 @@ func TestBlockSigner(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, blockSignerAddress, nil)
t.Log("contract code", common.ToHex(code))
t.Log("contract code", hexutil.Encode(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true

View file

@ -24,6 +24,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/contracts"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types"
@ -56,7 +57,7 @@ func TestRandomize(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, randomizeAddress, nil)
t.Log("contract code", common.ToHex(code))
t.Log("contract code", hexutil.Encode(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true

View file

@ -29,6 +29,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state"
@ -68,7 +69,7 @@ func TestValidator(t *testing.T) {
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel()
code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil)
t.Log("contract code", common.ToHex(code))
t.Log("contract code", hexutil.Encode(code))
f := func(key, val common.Hash) bool {
t.Log(key.Hex(), val.Hex())
return true

View file

@ -137,8 +137,8 @@ type BlockChain struct {
db ethdb.Database // Low level persistent database to store final content in
XDCxDb ethdb.XDCxDatabase
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
gcproc time.Duration // Accumulates canonical block processing for trie dumping
triegc *prque.Prque[int64, common.Hash] // Priority queue mapping block numbers to tries to gc
gcproc time.Duration // Accumulates canonical block processing for trie dumping
hc *HeaderChain
rmLogsFeed event.Feed
@ -209,7 +209,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
chainConfig: chainConfig,
cacheConfig: cacheConfig,
db: db,
triegc: prque.New(nil),
triegc: prque.New[int64, common.Hash](nil),
stateCache: state.NewDatabase(db),
quit: make(chan struct{}),
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
@ -957,7 +957,7 @@ func (bc *BlockChain) saveData() {
author, _ := bc.Engine().Author(recent.Header())
if tradingService != nil {
tradingRoot, _ := tradingService.GetTradingStateRoot(recent, author)
if !common.EmptyHash(tradingRoot) && tradingTriedb != nil {
if !tradingRoot.IsZero() && tradingTriedb != nil {
if err := tradingTriedb.Commit(tradingRoot, true); err != nil {
log.Error("Failed to commit trading state recent state trie", "err", err)
}
@ -965,7 +965,7 @@ func (bc *BlockChain) saveData() {
}
if lendingService != nil {
lendingRoot, _ := lendingService.GetLendingStateRoot(recent, author)
if !common.EmptyHash(lendingRoot) && lendingTriedb != nil {
if !lendingRoot.IsZero() && lendingTriedb != nil {
if err := lendingTriedb.Commit(lendingRoot, true); err != nil {
log.Error("Failed to commit lending state recent state trie", "err", err)
}
@ -975,17 +975,17 @@ func (bc *BlockChain) saveData() {
}
}
for !bc.triegc.Empty() {
triedb.Dereference(bc.triegc.PopItem().(common.Hash))
triedb.Dereference(bc.triegc.PopItem())
}
if tradingTriedb != nil && lendingTriedb != nil {
if tradingService.GetTriegc() != nil {
for !tradingService.GetTriegc().Empty() {
tradingTriedb.Dereference(tradingService.GetTriegc().PopItem().(common.Hash))
tradingTriedb.Dereference(tradingService.GetTriegc().PopItem())
}
}
if lendingService.GetTriegc() != nil {
for !lendingService.GetTriegc().Empty() {
lendingTriedb.Dereference(lendingService.GetTriegc().PopItem().(common.Hash))
lendingTriedb.Dereference(lendingService.GetTriegc().PopItem())
}
}
}
@ -1328,7 +1328,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
bc.triegc.Push(root, number)
break
}
triedb.Dereference(root.(common.Hash))
triedb.Dereference(root)
}
if tradingService != nil {
for !tradingService.GetTriegc().Empty() {
@ -1337,7 +1337,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
tradingService.GetTriegc().Push(tradingRoot, number)
break
}
tradingTrieDb.Dereference(tradingRoot.(common.Hash))
tradingTrieDb.Dereference(tradingRoot)
}
}
if lendingService != nil {
@ -1347,7 +1347,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
lendingService.GetTriegc().Push(lendingRoot, number)
break
}
lendingTrieDb.Dereference(lendingRoot.(common.Hash))
lendingTrieDb.Dereference(lendingRoot)
}
}
}
@ -2123,7 +2123,7 @@ const statsReportLimit = 8 * time.Second
// report prints statistics if some number of blocks have been processed
// or more than a few seconds have passed since the last message.
func (st *insertStats) report(chain []*types.Block, index int, cache common.StorageSize) {
func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize) {
// Fetch the timings for the batch
var (
now = mclock.Now()
@ -2138,7 +2138,7 @@ func (st *insertStats) report(chain []*types.Block, index int, cache common.Stor
context := []interface{}{
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
"number", end.Number(), "hash", end.Hash(), "cache", cache,
"number", end.Number(), "hash", end.Hash(), "dirty", dirty,
}
if st.queued > 0 {
context = append(context, []interface{}{"queued", st.queued}...)

View file

@ -14,15 +14,14 @@
// 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/>.
//go:build none
// +build none
/*
The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
go run mkalloc.go genesis.json
go run mkalloc.go genesis.json
*/
package main
@ -52,7 +51,8 @@ func makelist(g *core.Genesis) allocList {
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
panic(fmt.Sprintf("can't encode account %x", addr))
}
a = append(a, allocItem{addr.Big(), account.Balance})
bigAddr := new(big.Int).SetBytes(addr.Bytes())
a = append(a, allocItem{bigAddr, account.Balance})
}
sort.Sort(a)
return a

View file

@ -282,7 +282,7 @@ func (s *stateObject) updateTrie(db Database) Trie {
continue
}
// Encoding []byte cannot fail, ok to ignore the error.
v, _ := rlp.EncodeToBytes(bytes.TrimLeft(value[:], "\x00"))
v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
s.setError(tr.TryUpdate(key[:], v))
}
return tr

View file

@ -1,4 +1,4 @@
// Copyright 2015 The go-ethereum Authors
// 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
@ -14,31 +14,35 @@
// 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 abi
package state
import (
"bytes"
"math/big"
"reflect"
"testing"
"github.com/XinFinOrg/XDPoSChain/common"
)
func TestNumberTypes(t *testing.T) {
ubytes := make([]byte, 32)
ubytes[31] = 1
unsigned := U256(big.NewInt(1))
if !bytes.Equal(unsigned, ubytes) {
t.Errorf("expected %x got %x", ubytes, unsigned)
func BenchmarkCutOriginal(b *testing.B) {
value := common.HexToHash("0x01")
for i := 0; i < b.N; i++ {
bytes.TrimLeft(value[:], "\x00")
}
}
func TestSigned(t *testing.T) {
if isSigned(reflect.ValueOf(uint(10))) {
t.Error("signed")
func BenchmarkCutsetterFn(b *testing.B) {
value := common.HexToHash("0x01")
cutSetFn := func(r rune) bool {
return int32(r) == int32(0)
}
if !isSigned(reflect.ValueOf(int(10))) {
t.Error("not signed")
for i := 0; i < b.N; i++ {
bytes.TrimLeftFunc(value[:], cutSetFn)
}
}
func BenchmarkCutCustomTrim(b *testing.B) {
value := common.HexToHash("0x01")
for i := 0; i < b.N; i++ {
common.TrimLeftZeroes(value[:])
}
}

View file

@ -100,7 +100,7 @@ func (s *StateSuite) TestNull(c *checker.C) {
s.state.SetState(address, common.Hash{}, value)
s.state.Commit(false)
value = s.state.GetState(address, common.Hash{})
if !common.EmptyHash(value) {
if !value.IsZero() {
c.Errorf("expected empty hash. got %x", value)
}
}

View file

@ -51,7 +51,7 @@ func GetTRC21FeeCapacityFromState(statedb *StateDB) map[common.Address]*big.Int
for i := uint64(0); i < tokenCount; i++ {
key := GetLocDynamicArrAtElement(slotTokensHash, i, 1)
value := statedb.GetState(common.TRC21IssuerSMC, key)
if !common.EmptyHash(value) {
if !value.IsZero() {
token := common.BytesToAddress(value.Bytes())
balanceKey := GetLocMappingAtKey(token.Hash(), slotTokensState)
balanceHash := statedb.GetState(common.TRC21IssuerSMC, common.BigToHash(balanceKey))
@ -68,14 +68,14 @@ func PayFeeWithTRC21TxFail(statedb *StateDB, from common.Address, token common.A
slotBalanceTrc21 := SlotTRC21Token["balances"]
balanceKey := GetLocMappingAtKey(from.Hash(), slotBalanceTrc21)
balanceHash := statedb.GetState(token, common.BigToHash(balanceKey))
if !common.EmptyHash(balanceHash) {
if !balanceHash.IsZero() {
balance := balanceHash.Big()
feeUsed := big.NewInt(0)
if balance.Cmp(feeUsed) <= 0 {
return
}
issuerTokenKey := GetLocSimpleVariable(SlotTRC21Token["issuer"])
if common.EmptyHash(issuerTokenKey) {
if issuerTokenKey.IsZero() {
return
}
issuerAddr := common.BytesToAddress(statedb.GetState(token, issuerTokenKey).Bytes())
@ -106,7 +106,7 @@ func ValidateTRC21Tx(statedb *StateDB, from common.Address, token common.Address
balanceKey := GetLocMappingAtKey(from.Hash(), slotBalanceTrc21)
balanceHash := statedb.GetState(token, common.BigToHash(balanceKey))
if !common.EmptyHash(balanceHash) {
if !balanceHash.IsZero() {
balance := balanceHash.Big()
minFeeTokenKey := GetLocSimpleVariable(SlotTRC21Token["minFee"])
minFeeHash := statedb.GetState(token, minFeeTokenKey)
@ -129,7 +129,7 @@ func ValidateTRC21Tx(statedb *StateDB, from common.Address, token common.Address
} else {
// we both accept tx with balance = 0 and fee = 0
minFeeTokenKey := GetLocSimpleVariable(SlotTRC21Token["minFee"])
if !common.EmptyHash(minFeeTokenKey) {
if !minFeeTokenKey.IsZero() {
return true
}
}

View file

@ -90,7 +90,7 @@ func TestStateProcessorErrors(t *testing.T) {
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
)
defer blockchain.Stop()
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
bigNumber := new(big.Int).SetBytes(common.MaxHash.Bytes())
tooBigNumber := new(big.Int).Set(bigNumber)
tooBigNumber.Add(tooBigNumber, common.Big1)
for i, tt := range []struct {

View file

@ -23,7 +23,6 @@ import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
cmath "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto"
@ -397,7 +396,10 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
} else {
effectiveTip := st.gasPrice
if st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
effectiveTip = new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee)
if effectiveTip.Cmp(st.gasTipCap) > 0 {
effectiveTip = st.gasTipCap
}
}
st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))
}

View file

@ -997,7 +997,7 @@ func (pool *LendingPool) promoteExecutables(accounts []common.Address) {
if pending > pool.config.GlobalSlots {
pendingBeforeCap := pending
// Assemble a spam order to penalize large transactors first
spammers := prque.New(nil)
spammers := prque.New[int64, common.Address](nil)
for addr, list := range pool.pending {
// Only evict transactions from high rollers
if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
@ -1009,12 +1009,12 @@ func (pool *LendingPool) promoteExecutables(accounts []common.Address) {
for pending > pool.config.GlobalSlots && !spammers.Empty() {
// Retrieve the next offender if not local address
offender, _ := spammers.Pop()
offenders = append(offenders, offender.(common.Address))
offenders = append(offenders, offender)
// Equalize balances until all the same or below threshold
if len(offenders) > 1 {
// Calculate the equalization threshold for all current offenders
threshold := pool.pending[offender.(common.Address)].Len()
threshold := pool.pending[offender].Len()
// Iteratively reduce all offenders until below limit or threshold reached
for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold {

View file

@ -492,7 +492,7 @@ func (pool *OrderPool) validateOrder(tx *types.OrderTransaction) error {
var signer = types.OrderTxSigner{}
if !tx.IsCancelledOrder() {
if !common.EmptyHash(tx.OrderHash()) {
if !tx.OrderHash().IsZero() {
if signer.Hash(tx) != tx.OrderHash() {
return ErrInvalidOrderHash
}
@ -914,7 +914,7 @@ func (pool *OrderPool) promoteExecutables(accounts []common.Address) {
if pending > pool.config.GlobalSlots {
pendingBeforeCap := pending
// Assemble a spam order to penalize large transactors first
spammers := prque.New(nil)
spammers := prque.New[int64, common.Address](nil)
for addr, list := range pool.pending {
// Only evict transactions from high rollers
if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
@ -926,12 +926,12 @@ func (pool *OrderPool) promoteExecutables(accounts []common.Address) {
for pending > pool.config.GlobalSlots && !spammers.Empty() {
// Retrieve the next offender if not local address
offender, _ := spammers.Pop()
offenders = append(offenders, offender.(common.Address))
offenders = append(offenders, offender)
// Equalize balances until all the same or below threshold
if len(offenders) > 1 {
// Calculate the equalization threshold for all current offenders
threshold := pool.pending[offender.(common.Address)].Len()
threshold := pool.pending[offender].Len()
// Iteratively reduce all offenders until below limit or threshold reached
for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold {

View file

@ -1535,7 +1535,7 @@ func (pool *TxPool) truncatePending() {
pendingBeforeCap := pending
// Assemble a spam order to penalize large transactors first
spammers := prque.New(nil)
spammers := prque.New[int64, common.Address](nil)
for addr, list := range pool.pending {
// Only evict transactions from high rollers
if !pool.locals.contains(addr) && uint64(list.Len()) > pool.config.AccountSlots {
@ -1547,12 +1547,12 @@ func (pool *TxPool) truncatePending() {
for pending > pool.config.GlobalSlots && !spammers.Empty() {
// Retrieve the next offender if not local address
offender, _ := spammers.Pop()
offenders = append(offenders, offender.(common.Address))
offenders = append(offenders, offender)
// Equalize balances until all the same or below threshold
if len(offenders) > 1 {
// Calculate the equalization threshold for all current offenders
threshold := pool.pending[offender.(common.Address)].Len()
threshold := pool.pending[offender].Len()
// Iteratively reduce all offenders until below limit or threshold reached
for pending > pool.config.GlobalSlots && pool.pending[offenders[len(offenders)-2]].Len() > threshold {

View file

@ -0,0 +1,147 @@
// 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"
"fmt"
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/rlp"
"github.com/holiman/uint256"
)
func decodeEncode(input []byte, val interface{}) error {
if err := rlp.DecodeBytes(input, val); err != nil {
// not valid rlp, nothing to do
return nil
}
// If it _were_ valid rlp, we can encode it again
output, err := rlp.EncodeToBytes(val)
if err != nil {
return err
}
if !bytes.Equal(input, output) {
return fmt.Errorf("encode-decode is not equal, \ninput : %x\noutput: %x", input, output)
}
return nil
}
func FuzzRLP(f *testing.F) {
f.Fuzz(fuzzRlp)
}
func fuzzRlp(t *testing.T, input []byte) {
if len(input) == 0 || len(input) > 500*1024 {
return
}
rlp.Split(input)
if elems, _, err := rlp.SplitList(input); err == nil {
rlp.CountValues(elems)
}
rlp.NewStream(bytes.NewReader(input), 0).Decode(new(interface{}))
if err := decodeEncode(input, new(interface{})); err != nil {
t.Fatal(err)
}
{
var v struct {
Int uint
String string
Bytes []byte
}
if err := decodeEncode(input, &v); err != nil {
t.Fatal(err)
}
}
{
type Types struct {
Bool bool
Raw rlp.RawValue
Slice []*Types
Iface []interface{}
}
var v Types
if err := decodeEncode(input, &v); err != nil {
t.Fatal(err)
}
}
{
type AllTypes struct {
Int uint
String string
Bytes []byte
Bool bool
Raw rlp.RawValue
Slice []*AllTypes
Array [3]*AllTypes
Iface []interface{}
}
var v AllTypes
if err := decodeEncode(input, &v); err != nil {
t.Fatal(err)
}
}
{
if err := decodeEncode(input, [10]byte{}); err != nil {
t.Fatal(err)
}
}
{
var v struct {
Byte [10]byte
Rool [10]bool
}
if err := decodeEncode(input, &v); err != nil {
t.Fatal(err)
}
}
{
var h Header
if err := decodeEncode(input, &h); err != nil {
t.Fatal(err)
}
var b Block
if err := decodeEncode(input, &b); err != nil {
t.Fatal(err)
}
var tx Transaction
if err := decodeEncode(input, &tx); err != nil {
t.Fatal(err)
}
var txs Transactions
if err := decodeEncode(input, &txs); err != nil {
t.Fatal(err)
}
var rs Receipts
if err := decodeEncode(input, &rs); err != nil {
t.Fatal(err)
}
}
{
var v struct {
AnIntPtr *big.Int
AnInt big.Int
AnU256Ptr *uint256.Int
AnU256 uint256.Int
NotAnU256 [4]uint64
}
if err := decodeEncode(input, &v); err != nil {
t.Fatal(err)
}
}
}

View file

@ -27,7 +27,7 @@ import (
"time"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
@ -363,10 +363,16 @@ func (tx *Transaction) EffectiveGasTip(baseFee *big.Int) (*big.Int, error) {
}
var err error
gasFeeCap := tx.GasFeeCap()
if gasFeeCap.Cmp(baseFee) == -1 {
if gasFeeCap.Cmp(baseFee) < 0 {
err = ErrGasFeeCapTooLow
}
return math.BigMin(tx.GasTipCap(), gasFeeCap.Sub(gasFeeCap, baseFee)), err
gasFeeCap = gasFeeCap.Sub(gasFeeCap, baseFee)
gasTipCap := tx.GasTipCap()
if gasTipCap.Cmp(gasFeeCap) < 0 {
return gasTipCap, err
}
return gasFeeCap, err
}
// EffectiveGasTipValue is identical to EffectiveGasTip, but does not return an
@ -452,7 +458,10 @@ func (tx *Transaction) AsMessage(s Signer, balanceFee, blockNumber, baseFee *big
}
} else if baseFee != nil {
// If baseFee provided, set gasPrice to effectiveGasPrice.
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
msg.gasPrice = msg.gasPrice.Add(msg.gasTipCap, baseFee)
if msg.gasPrice.Cmp(msg.gasFeeCap) > 0 {
msg.gasPrice.Set(msg.gasFeeCap)
}
}
var err error
@ -513,7 +522,7 @@ func (tx *Transaction) IsSigningTransaction() bool {
if len(data) != (32*2 + 4) {
return false
}
method := common.ToHex(data[0:4])
method := hexutil.Encode(data[0:4])
return method == common.SignMethod
}
@ -524,7 +533,7 @@ func (tx *Transaction) IsVotingTransaction() (bool, *common.Address) {
}
var end int
data := tx.Data()
method := common.ToHex(data[0:4])
method := hexutil.Encode(data[0:4])
if method == common.VoteMethod || method == common.ProposeMethod || method == common.ResignMethod {
end = len(data)
} else if method == common.UnvoteMethod {
@ -558,7 +567,7 @@ func (tx *Transaction) IsXDCXApplyTransaction() bool {
if len(data) != (32 + 4) {
return false
}
method := common.ToHex(data[0:4])
method := hexutil.Encode(data[0:4])
return method == common.XDCXApplyMethod
}
@ -581,7 +590,7 @@ func (tx *Transaction) IsXDCZApplyTransaction() bool {
if len(data) != (32 + 4) {
return false
}
method := common.ToHex(data[0:4])
method := hexutil.Encode(data[0:4])
return method == common.XDCZApplyMethod
}

View file

@ -17,8 +17,9 @@
package vm
import (
"math"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/holiman/uint256"
)

View file

@ -20,10 +20,10 @@ import (
"crypto/sha256"
"encoding/binary"
"errors"
"math"
"math/big"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/core/vm/privacy"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/blake2b"
@ -346,7 +346,12 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
}
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
// Calculate the gas cost of the operation
gas := new(big.Int).Set(math.BigMax(modLen, baseLen))
gas := new(big.Int)
if modLen.Cmp(baseLen) < 0 {
gas.Set(baseLen)
} else {
gas.Set(modLen)
}
if c.eip2565 {
// EIP-2565 has three changes
// 1. Different multComplexity (inlined here)
@ -360,7 +365,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
gas = gas.Div(gas, big8)
gas.Mul(gas, gas)
gas.Mul(gas, math.BigMax(adjExpLen, big1))
if adjExpLen.Cmp(big1) > 0 {
gas.Mul(gas, adjExpLen)
}
// 2. Different divisor (`GQUADDIVISOR`) (3)
gas.Div(gas, big3)
if gas.BitLen() > 64 {
@ -373,7 +380,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
return gas.Uint64()
}
gas = modexpMultComplexity(gas)
gas.Mul(gas, math.BigMax(adjExpLen, big1))
if adjExpLen.Cmp(big1) > 0 {
gas.Mul(gas, adjExpLen)
}
gas.Div(gas, big20)
if gas.BitLen() > 64 {

View file

@ -14,12 +14,31 @@
// 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 rlp
package vm
import "testing"
import (
"testing"
func Fuzz(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
fuzz(data)
"github.com/XinFinOrg/XDPoSChain/common"
)
func FuzzPrecompiledContracts(f *testing.F) {
// Create list of addresses
var addrs []common.Address
for k := range allPrecompiles {
addrs = append(addrs, k)
}
f.Fuzz(func(t *testing.T, addr uint8, input []byte) {
a := addrs[int(addr)%len(addrs)]
p := allPrecompiles[a]
gas := p.RequiredGas(input)
if gas > 10_000_000 {
return
}
inWant := string(input)
RunPrecompiledContract(nil, p, input, gas)
if inHave := string(input); inWant != inHave {
t.Errorf("Precompiled %v modified input data", a)
}
})
}

View file

@ -22,7 +22,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
GasCost math.HexOrDecimal64 `json:"gasCost"`
Memory hexutil.Bytes `json:"memory"`
MemorySize int `json:"memSize"`
Stack []uint256.Int `json:"stack"`
Stack []hexutil.U256 `json:"stack"`
ReturnData hexutil.Bytes `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
@ -38,7 +38,12 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.GasCost = math.HexOrDecimal64(s.GasCost)
enc.Memory = s.Memory
enc.MemorySize = s.MemorySize
enc.Stack = s.Stack
if s.Stack != nil {
enc.Stack = make([]hexutil.U256, len(s.Stack))
for k, v := range s.Stack {
enc.Stack[k] = hexutil.U256(v)
}
}
enc.ReturnData = s.ReturnData
enc.Storage = s.Storage
enc.Depth = s.Depth
@ -58,7 +63,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
GasCost *math.HexOrDecimal64 `json:"gasCost"`
Memory *hexutil.Bytes `json:"memory"`
MemorySize *int `json:"memSize"`
Stack []uint256.Int `json:"stack"`
Stack []hexutil.U256 `json:"stack"`
ReturnData *hexutil.Bytes `json:"returnData"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth *int `json:"depth"`
@ -88,7 +93,10 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s.MemorySize = *dec.MemorySize
}
if dec.Stack != nil {
s.Stack = dec.Stack
s.Stack = make([]uint256.Int, len(dec.Stack))
for k, v := range dec.Stack {
s.Stack[k] = uint256.Int(v)
}
}
if dec.ReturnData != nil {
s.ReturnData = *dec.ReturnData

View file

@ -81,6 +81,7 @@ type structLogMarshaling struct {
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
ReturnData hexutil.Bytes
Stack []hexutil.U256
OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
ErrorString string `json:"error"` // adds call to ErrorString() in MarshalJSON
}

View file

@ -18,13 +18,11 @@ package runtime
import (
"testing"
"github.com/XinFinOrg/XDPoSChain/core/vm/runtime"
)
func Fuzz(f *testing.F) {
func FuzzVmRuntime(f *testing.F) {
f.Fuzz(func(t *testing.T, code, input []byte) {
runtime.Execute(code, input, &runtime.Config{
Execute(code, input, &Config{
GasLimit: 12000000,
})
})

View file

@ -682,7 +682,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
}
}
// If the head fetch already found an ancestor, return
if !common.EmptyHash(hash) {
if !hash.IsZero() {
if int64(number) <= floor {
p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor)
return 0, errInvalidAncestor

View file

@ -70,7 +70,7 @@ type queue struct {
// Headers are "special", they download in batches, supported by a skeleton chain
headerHead common.Hash // [eth/62] Hash of the last queued header to verify order
headerTaskPool map[uint64]*types.Header // [eth/62] Pending header retrieval tasks, mapping starting indexes to skeleton headers
headerTaskQueue *prque.Prque // [eth/62] Priority queue of the skeleton indexes to fetch the filling headers for
headerTaskQueue *prque.Prque[int64, uint64] // [eth/62] Priority queue of the skeleton indexes to fetch the filling headers for
headerPeerMiss map[string]map[uint64]struct{} // [eth/62] Set of per-peer header batches known to be unavailable
headerPendPool map[string]*fetchRequest // [eth/62] Currently pending header retrieval operations
headerResults []*types.Header // [eth/62] Result cache accumulating the completed headers
@ -79,15 +79,15 @@ type queue struct {
headerContCh chan bool // [eth/62] Channel to notify when header download finishes
// All data retrievals below are based on an already assembles header chain
blockTaskPool map[common.Hash]*types.Header // [eth/62] Pending block (body) retrieval tasks, mapping hashes to headers
blockTaskQueue *prque.Prque // [eth/62] Priority queue of the headers to fetch the blocks (bodies) for
blockPendPool map[string]*fetchRequest // [eth/62] Currently pending block (body) retrieval operations
blockDonePool map[common.Hash]struct{} // [eth/62] Set of the completed block (body) fetches
blockTaskPool map[common.Hash]*types.Header // [eth/62] Pending block (body) retrieval tasks, mapping hashes to headers
blockTaskQueue *prque.Prque[int64, *types.Header] // [eth/62] Priority queue of the headers to fetch the blocks (bodies) for
blockPendPool map[string]*fetchRequest // [eth/62] Currently pending block (body) retrieval operations
blockDonePool map[common.Hash]struct{} // [eth/62] Set of the completed block (body) fetches
receiptTaskPool map[common.Hash]*types.Header // [eth/63] Pending receipt retrieval tasks, mapping hashes to headers
receiptTaskQueue *prque.Prque // [eth/63] Priority queue of the headers to fetch the receipts for
receiptPendPool map[string]*fetchRequest // [eth/63] Currently pending receipt retrieval operations
receiptDonePool map[common.Hash]struct{} // [eth/63] Set of the completed receipt fetches
receiptTaskPool map[common.Hash]*types.Header // [eth/63] Pending receipt retrieval tasks, mapping hashes to headers
receiptTaskQueue *prque.Prque[int64, *types.Header] // [eth/63] Priority queue of the headers to fetch the receipts for
receiptPendPool map[string]*fetchRequest // [eth/63] Currently pending receipt retrieval operations
receiptDonePool map[common.Hash]struct{} // [eth/63] Set of the completed receipt fetches
resultCache []*fetchResult // Downloaded but not yet delivered fetch results
resultOffset uint64 // Offset of the first cached fetch result in the block chain
@ -105,11 +105,11 @@ func newQueue() *queue {
headerPendPool: make(map[string]*fetchRequest),
headerContCh: make(chan bool),
blockTaskPool: make(map[common.Hash]*types.Header),
blockTaskQueue: prque.New(nil),
blockTaskQueue: prque.New[int64, *types.Header](nil),
blockPendPool: make(map[string]*fetchRequest),
blockDonePool: make(map[common.Hash]struct{}),
receiptTaskPool: make(map[common.Hash]*types.Header),
receiptTaskQueue: prque.New(nil),
receiptTaskQueue: prque.New[int64, *types.Header](nil),
receiptPendPool: make(map[string]*fetchRequest),
receiptDonePool: make(map[common.Hash]struct{}),
resultCache: make([]*fetchResult, blockCacheItems),
@ -277,7 +277,7 @@ func (q *queue) ScheduleSkeleton(from uint64, skeleton []*types.Header) {
}
// Shedule all the header retrieval tasks for the skeleton assembly
q.headerTaskPool = make(map[uint64]*types.Header)
q.headerTaskQueue = prque.New(nil)
q.headerTaskQueue = prque.New[int64, uint64](nil)
q.headerPeerMiss = make(map[string]map[uint64]struct{}) // Reset availability to correct invalid chains
q.headerResults = make([]*types.Header, len(skeleton)*MaxHeaderFetch)
q.headerProced = 0
@ -427,12 +427,12 @@ func (q *queue) ReserveHeaders(p *peerConnection, count int) *fetchRequest {
for send == 0 && !q.headerTaskQueue.Empty() {
from, _ := q.headerTaskQueue.Pop()
if q.headerPeerMiss[p.id] != nil {
if _, ok := q.headerPeerMiss[p.id][from.(uint64)]; ok {
skip = append(skip, from.(uint64))
if _, ok := q.headerPeerMiss[p.id][from]; ok {
skip = append(skip, from)
continue
}
}
send = from.(uint64)
send = from
}
// Merge all the skipped batches back
for _, from := range skip {
@ -484,7 +484,7 @@ func (q *queue) ReserveReceipts(p *peerConnection, count int) (*fetchRequest, bo
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque,
func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque[int64, *types.Header],
pendPool map[string]*fetchRequest, donePool map[common.Hash]struct{}, isNoop func(*types.Header) bool) (*fetchRequest, bool, error) {
// Short circuit if the pool has been depleted, or if the peer's already
// downloading something (sanity check not to corrupt state)
@ -503,7 +503,7 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common
progress := false
for proc := 0; proc < space && len(send) < count && !taskQueue.Empty(); proc++ {
header := taskQueue.PopItem().(*types.Header)
header := taskQueue.PopItem()
hash := header.Hash()
// If we're the first to request this task, initialise the result container
@ -586,12 +586,12 @@ func (q *queue) CancelReceipts(request *fetchRequest) {
}
// Cancel aborts a fetch request, returning all pending hashes to the task queue.
func (q *queue) cancel(request *fetchRequest, taskQueue *prque.Prque, pendPool map[string]*fetchRequest) {
func (q *queue) cancel(request *fetchRequest, taskQueue interface{}, pendPool map[string]*fetchRequest) {
if request.From > 0 {
taskQueue.Push(request.From, -int64(request.From))
taskQueue.(*prque.Prque[int64, uint64]).Push(request.From, -int64(request.From))
}
for _, header := range request.Headers {
taskQueue.Push(header, -int64(header.Number.Uint64()))
taskQueue.(*prque.Prque[int64, *types.Header]).Push(header, -int64(header.Number.Uint64()))
}
delete(pendPool, request.Peer.id)
}
@ -650,7 +650,7 @@ func (q *queue) ExpireReceipts(timeout time.Duration) map[string]int {
// Note, this method expects the queue lock to be already held. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, taskQueue *prque.Prque, timeoutMeter *metrics.Meter) map[string]int {
func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest, taskQueue interface{}, timeoutMeter *metrics.Meter) map[string]int {
// Iterate over the expired requests and return each to the queue
expiries := make(map[string]int)
for id, request := range pendPool {
@ -660,10 +660,10 @@ func (q *queue) expire(timeout time.Duration, pendPool map[string]*fetchRequest,
// Return any non satisfied requests to the pool
if request.From > 0 {
taskQueue.Push(request.From, -int64(request.From))
taskQueue.(*prque.Prque[int64, uint64]).Push(request.From, -int64(request.From))
}
for _, header := range request.Headers {
taskQueue.Push(header, -int64(header.Number.Uint64()))
taskQueue.(*prque.Prque[int64, *types.Header]).Push(header, -int64(header.Number.Uint64()))
}
// Add the peer to the expiry report along the the number of failed requests
expiries[id] = len(request.Headers)
@ -804,7 +804,7 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt) (int,
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque,
func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQueue *prque.Prque[int64, *types.Header],
pendPool map[string]*fetchRequest, donePool map[common.Hash]struct{}, reqTimer *metrics.Timer,
results int, reconstruct func(header *types.Header, index int, result *fetchResult) error) (int, error) {

View file

@ -131,11 +131,10 @@ type Fetcher struct {
completing map[common.Hash]*announce // Blocks with headers, currently body-completing
// Block cache
queue *prque.Prque // Queue containing the import operations (block number sorted)
queues map[string]int // Per peer block counts to prevent memory exhaustion
queued map[common.Hash]*inject // Set of already queued blocks (to dedup imports)
queue *prque.Prque[int64, *inject] // Queue containing the import operations (block number sorted)
queues map[string]int // Per peer block counts to prevent memory exhaustion
queued map[common.Hash]*inject // Set of already queued blocks (to dedup imports)
knowns *lru.Cache[common.Hash, struct{}]
// Callbacks
getBlock blockRetrievalFn // Retrieves a block from the local chain
verifyHeader headerVerifierFn // Checks if a block's headers have a valid proof of work
@ -170,7 +169,7 @@ func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, handlePropose
fetching: make(map[common.Hash]*announce),
fetched: make(map[common.Hash][]*announce),
completing: make(map[common.Hash]*announce),
queue: prque.New(nil),
queue: prque.New[int64, *inject](nil),
queues: make(map[string]int),
queued: make(map[common.Hash]*inject),
knowns: lru.NewCache[common.Hash, struct{}](blockLimit),
@ -304,7 +303,7 @@ func (f *Fetcher) loop() {
// Import any queued blocks that could potentially fit
height := f.chainHeight()
for !f.queue.Empty() {
op := f.queue.PopItem().(*inject)
op := f.queue.PopItem()
if f.queueChangeHook != nil {
f.queueChangeHook(op.block.Hash(), false)
}

View file

@ -527,7 +527,7 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er
if err != nil {
return err
}
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data))
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data))
}
func toBlockNumArg(number *big.Int) string {
@ -550,7 +550,7 @@ func (ec *Client) SendOrderTransaction(ctx context.Context, tx *types.OrderTrans
if err != nil {
return err
}
return ec.c.CallContext(ctx, nil, "XDCx_sendOrderRawTransaction", common.ToHex(data))
return ec.c.CallContext(ctx, nil, "XDCx_sendOrderRawTransaction", hexutil.Encode(data))
}
// SendLendingTransaction send lending to pool
@ -559,7 +559,7 @@ func (ec *Client) SendLendingTransaction(ctx context.Context, tx *types.LendingT
if err != nil {
return err
}
return ec.c.CallContext(ctx, nil, "XDCx_sendLendingRawTransaction", common.ToHex(data))
return ec.c.CallContext(ctx, nil, "XDCx_sendLendingRawTransaction", hexutil.Encode(data))
}
func toCallArg(msg ethereum.CallMsg) interface{} {

4
go.mod
View file

@ -4,7 +4,6 @@ go 1.22
require (
github.com/VictoriaMetrics/fastcache v1.12.2
github.com/aristanetworks/goarista v0.0.0-20231019142648-8c6f0862ab98
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6
github.com/cespare/cp v1.1.1
github.com/davecgh/go-spew v1.1.1
@ -48,10 +47,12 @@ require (
github.com/deckarep/golang-set v1.8.0
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498
github.com/ethereum/c-kzg-4844 v0.4.0
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/influxdata/influxdb-client-go/v2 v2.4.0
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
github.com/kylelemons/godebug v1.1.0
github.com/mattn/go-isatty v0.0.17
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/urfave/cli/v2 v2.27.5
gopkg.in/natefinch/lumberjack.v2 v2.2.1
@ -70,6 +71,7 @@ require (
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/kilic/bls12-381 v0.1.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect

9
go.sum
View file

@ -4,8 +4,6 @@ github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjC
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/aristanetworks/goarista v0.0.0-20231019142648-8c6f0862ab98 h1:7buXGE+m4OPjyo8rUJgA8RmARNMq+m99JJLR+Z+ZWN0=
github.com/aristanetworks/goarista v0.0.0-20231019142648-8c6f0862ab98/go.mod h1:DLTg9Gp4FAXF5EpqYBQnUeBbRsNLY7b2HR94TE5XQtE=
github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8=
github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
@ -65,6 +63,8 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@ -109,6 +109,8 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/karalabe/hid v1.0.0 h1:+/CIMNXhSU/zIJgnIvBD2nKHxS/bnRHhhs9xBryLpPo=
github.com/karalabe/hid v1.0.0/go.mod h1:Vr51f8rUOLYrfrWDFlV12GGQgM5AT8sVh+2fY4MPeu8=
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -173,6 +175,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/prometheus v1.7.2-0.20170814170113-3101606756c5 h1:K2PKeDFZidfjUWpXk05Gbxhwm8Rnz1l4O+u/bbbcCvc=
github.com/prometheus/prometheus v1.7.2-0.20170814170113-3101606756c5/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c=
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
@ -249,6 +253,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View file

@ -20,7 +20,6 @@ import (
"bytes"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
@ -87,28 +86,6 @@ func readGitFile(file string) string {
return strings.TrimSpace(string(content))
}
// CopyFile copies a file.
func CopyFile(dst, src string, mode os.FileMode) {
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
log.Fatal(err)
}
destFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
if err != nil {
log.Fatal(err)
}
defer destFile.Close()
srcFile, err := os.Open(src)
if err != nil {
log.Fatal(err)
}
defer srcFile.Close()
if _, err := io.Copy(destFile, srcFile); err != nil {
log.Fatal(err)
}
}
// GoTool returns the command that runs a go tool. This uses go from GOROOT instead of PATH
// so that go commands executed by build use the same version of Go as the 'host' that runs
// build code. e.g.

View file

@ -21,6 +21,7 @@ import (
"context"
"errors"
"fmt"
"math"
"math/big"
"strings"
"time"
@ -33,7 +34,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/common/sort"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
@ -383,12 +383,16 @@ func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (a
}
// NewAccount will create a new account and returns the address for the new account.
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
func (s *PrivateAccountAPI) NewAccount(password string) (common.AddressEIP55, error) {
acc, err := fetchKeystore(s.am).NewAccount(password)
if err == nil {
return acc.Address, nil
addrEIP55 := common.AddressEIP55(acc.Address)
log.Info("Your new key was generated", "address", addrEIP55.String())
log.Warn("Please backup your key file!", "path", acc.URL.Path)
log.Warn("Please remember your password!")
return addrEIP55, nil
}
return common.Address{}, err
return common.AddressEIP55{}, err
}
// fetchKeystore retrives the encrypted keystore from the account manager.
@ -1949,7 +1953,11 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
// if the transaction has been mined, compute the effective gas price
if baseFee != nil && blockHash != (common.Hash{}) {
// price = min(tip, gasFeeCap - baseFee) + baseFee
price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
price := new(big.Int).Add(tx.GasTipCap(), baseFee)
txGasFeeCap := tx.GasFeeCap()
if price.Cmp(txGasFeeCap) > 0 {
price = txGasFeeCap
}
result.GasPrice = (*hexutil.Big)(price)
} else {
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
@ -3499,6 +3507,15 @@ func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) {
api.b.SetHead(uint64(number))
}
// DbGet returns the raw value of a key stored in the database.
func (api *PrivateDebugAPI) DbGet(key string) (hexutil.Bytes, error) {
blob, err := common.ParseHexOrString(key)
if err != nil {
return nil, err
}
return api.b.ChainDb().Get(blob)
}
// PublicNetAPI offers network related RPC methods
type PublicNetAPI struct {
net *p2p.Server

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