/* Copyright 2021 Erigon contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package common import ( "bytes" "database/sql/driver" "encoding/hex" "fmt" "math/big" "math/rand" "reflect" "github.com/ledgerwatch/erigon-lib/common/hexutility" "github.com/ledgerwatch/erigon-lib/common/length" ) var ( hashT = reflect.TypeOf(Hash{}) ) const ( hexPrefix = `0x` ) // Hash represents the 32 byte Keccak256 hash of arbitrary data. type Hash [length.Hash]byte // BytesToHash sets b to hash. // If b is larger than len(h), b will be cropped from the left. func BytesToHash(b []byte) Hash { var h Hash h.SetBytes(b) return h } // CastToHash - sets b to hash // If b is larger than len(h), b will be cropped from the left. // panics if input is shorter than 32 bytes, see https://go.dev/doc/go1.17#language // faster than BytesToHash func CastToHash(b []byte) Hash { return *(*Hash)(b) } // BigToHash sets byte representation of b to hash. // If b is larger than len(h), b will be cropped from the left. func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // HexToHash sets byte representation of s to hash. // If b is larger than len(h), b will be cropped from the left. func HexToHash(s string) Hash { return BytesToHash(hexutility.FromHex(s)) } // Bytes gets the byte representation of the underlying hash. func (h Hash) Bytes() []byte { return h[:] } // Big converts a hash to a big integer. func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) } // Hex converts a hash to a hex string. func (h Hash) Hex() string { return hexutility.Encode(h[:]) } // TerminalString implements log.TerminalStringer, formatting a string for console // output during logging. func (h Hash) TerminalString() string { return fmt.Sprintf("%x…%x", h[:3], h[29:]) } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. func (h Hash) String() string { return h.Hex() } // Format implements fmt.Formatter. // Hash supports the %v, %s, %v, %x, %X and %d format verbs. func (h Hash) Format(s fmt.State, c rune) { 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. func (h *Hash) UnmarshalText(input []byte) error { return hexutility.UnmarshalFixedText("Hash", input, h[:]) } // UnmarshalJSON parses a hash in hex syntax. func (h *Hash) UnmarshalJSON(input []byte) error { return hexutility.UnmarshalFixedJSON(hashT, input, h[:]) } // MarshalText returns the hex representation of h. func (h Hash) MarshalText() ([]byte, error) { b := h[:] result := make([]byte, len(b)*2+2) copy(result, hexPrefix) hex.Encode(result[2:], b) return result, nil } // SetBytes sets the hash to the value of b. // If b is larger than len(h), b will be cropped from the left. func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { b = b[len(b)-length.Hash:] } copy(h[length.Hash-len(b):], b) } // Generate implements testing/quick.Generator. func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value { m := rand.Intn(len(h)) for i := len(h) - 1; i > m; i-- { h[i] = byte(rand.Uint32()) } return reflect.ValueOf(h) } // Scan implements Scanner for database/sql. func (h *Hash) Scan(src interface{}) error { srcB, ok := src.([]byte) if !ok { return fmt.Errorf("can't scan %T into Hash", src) } if len(srcB) != length.Hash { return fmt.Errorf("can't scan []byte of len %d into Hash, want %d", len(srcB), length.Hash) } copy(h[:], srcB) return nil } // Value implements valuer for database/sql. func (h Hash) Value() (driver.Value, error) { return h[:], nil } func FromHex(in string) []byte { return hexutility.MustDecodeHex(in) } type CodeRecord struct { BlockNumber uint64 TxNumber uint64 CodeHash Hash }