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 }