github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/rpc/types/block.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "math" 8 "math/big" 9 "strings" 10 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/ethereum/go-ethereum/common/hexutil" 13 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 14 ) 15 16 // BlockNumber represents decoding hex string to block values 17 type BlockNumber int64 18 19 var ( 20 // LatestBlockNumber mapping from "latest" to 0 for tm query 21 LatestBlockNumber = BlockNumber(0) 22 // PendingBlockNumber mapping from "pending" to -1 for tm query 23 PendingBlockNumber = BlockNumber(-1) 24 // EarliestBlockNumber mapping from "earliest" to (genesisHeight + 1) for tm query (earliest query not supported) 25 EarliestBlockNumber = BlockNumber(tmtypes.GetStartBlockHeight() + 1) 26 27 ErrResourceNotFound = errors.New("resource not found") 28 ) 29 30 // NewBlockNumber creates a new BlockNumber instance. 31 func NewBlockNumber(n *big.Int) BlockNumber { 32 return BlockNumber(n.Int64()) 33 } 34 35 // UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports: 36 // - "latest", "earliest" or "pending" as string arguments 37 // - the block number 38 // Returned errors: 39 // - an invalid block number error when the given argument isn't a known strings 40 // - an out of range error when the given block number is either too little or too large 41 func (bn *BlockNumber) UnmarshalJSON(data []byte) error { 42 input := strings.TrimSpace(string(data)) 43 if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { 44 input = input[1 : len(input)-1] 45 } 46 47 switch input { 48 case "earliest": 49 *bn = EarliestBlockNumber 50 return nil 51 case "latest": 52 *bn = LatestBlockNumber 53 return nil 54 case "pending": 55 *bn = PendingBlockNumber 56 return nil 57 } 58 59 blckNum, err := hexutil.DecodeUint64(input) 60 if err != nil { 61 return err 62 } 63 if blckNum > math.MaxInt64 { 64 return fmt.Errorf("blocknumber too high") 65 } 66 67 *bn = BlockNumber(blckNum) 68 return nil 69 } 70 71 // Int64 converts block number to primitive type 72 func (bn BlockNumber) Int64() int64 { 73 return int64(bn) 74 } 75 76 // TmHeight is a util function used for the Tendermint RPC client. It returns 77 // nil if the block number is "latest". Otherwise, it returns the pointer of the 78 // int64 value of the height. 79 func (bn BlockNumber) TmHeight() *int64 { 80 if bn == LatestBlockNumber { 81 return nil 82 } 83 height := bn.Int64() 84 return &height 85 } 86 87 type BlockNumberOrHash struct { 88 BlockNumber *BlockNumber `json:"blockNumber,omitempty"` 89 BlockHash *common.Hash `json:"blockHash,omitempty"` 90 RequireCanonical bool `json:"requireCanonical,omitempty"` 91 } 92 93 func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error { 94 type erased BlockNumberOrHash 95 e := erased{} 96 err := json.Unmarshal(data, &e) 97 if err == nil { 98 if e.BlockNumber != nil && e.BlockHash != nil { 99 return fmt.Errorf("cannot specify both BlockHash and BlockNumber, choose one or the other") 100 } 101 bnh.BlockNumber = e.BlockNumber 102 bnh.BlockHash = e.BlockHash 103 bnh.RequireCanonical = e.RequireCanonical 104 return nil 105 } 106 var input string 107 err = json.Unmarshal(data, &input) 108 if err != nil { 109 return err 110 } 111 switch input { 112 case "earliest": 113 bn := EarliestBlockNumber 114 bnh.BlockNumber = &bn 115 return nil 116 case "latest": 117 bn := LatestBlockNumber 118 bnh.BlockNumber = &bn 119 return nil 120 case "pending": 121 bn := PendingBlockNumber 122 bnh.BlockNumber = &bn 123 return nil 124 default: 125 if len(input) == 66 { 126 hash := common.Hash{} 127 err := hash.UnmarshalText([]byte(input)) 128 if err != nil { 129 return err 130 } 131 bnh.BlockHash = &hash 132 return nil 133 } else { 134 blckNum, err := hexutil.DecodeUint64(input) 135 if err != nil { 136 return err 137 } 138 if blckNum > math.MaxInt64 { 139 return fmt.Errorf("blocknumber too high") 140 } 141 bn := BlockNumber(blckNum) 142 bnh.BlockNumber = &bn 143 return nil 144 } 145 } 146 } 147 148 func (bnh *BlockNumberOrHash) Number() (BlockNumber, bool) { 149 if bnh.BlockNumber != nil { 150 return *bnh.BlockNumber, true 151 } 152 return BlockNumber(0), false 153 } 154 155 func (bnh *BlockNumberOrHash) Hash() (common.Hash, bool) { 156 if bnh.BlockHash != nil { 157 return *bnh.BlockHash, true 158 } 159 return common.Hash{}, false 160 } 161 162 func BlockNumberOrHashWithNumber(blockNr BlockNumber) BlockNumberOrHash { 163 return BlockNumberOrHash{ 164 BlockNumber: &blockNr, 165 BlockHash: nil, 166 RequireCanonical: false, 167 } 168 } 169 170 func BlockNumberOrHashWithHash(hash common.Hash, canonical bool) BlockNumberOrHash { 171 return BlockNumberOrHash{ 172 BlockNumber: nil, 173 BlockHash: &hash, 174 RequireCanonical: canonical, 175 } 176 }