package migration32 import ( "encoding/binary" "fmt" "io" "github.com/btcsuite/btcd/wire" lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21" ) var ( // Big endian is the preferred byte order, due to cursor scans over // integer keys iterating in order. byteOrder = binary.BigEndian ) // ReadElement is a one-stop utility function to deserialize any datastructure // encoded using the serialization format of the database. func ReadElement(r io.Reader, element interface{}) error { switch e := element.(type) { case *uint32: if err := binary.Read(r, byteOrder, e); err != nil { return err } case *lnwire.MilliSatoshi: var a uint64 if err := binary.Read(r, byteOrder, &a); err != nil { return err } *e = lnwire.MilliSatoshi(a) case *[]byte: bytes, err := wire.ReadVarBytes(r, 0, 66000, "[]byte") if err != nil { return err } *e = bytes case *int64, *uint64: if err := binary.Read(r, byteOrder, e); err != nil { return err } case *bool: if err := binary.Read(r, byteOrder, e); err != nil { return err } case *int32: if err := binary.Read(r, byteOrder, e); err != nil { return err } default: return UnknownElementType{"ReadElement", e} } return nil } // ReadElements deserializes a variable number of elements into the passed // io.Reader, with each element being deserialized according to the ReadElement // function. func ReadElements(r io.Reader, elements ...interface{}) error { for _, element := range elements { err := ReadElement(r, element) if err != nil { return err } } return nil } // UnknownElementType is an error returned when the codec is unable to encode or // decode a particular type. type UnknownElementType struct { method string element interface{} } // Error returns the name of the method that encountered the error, as well as // the type that was unsupported. func (e UnknownElementType) Error() string { return fmt.Sprintf("Unknown type in %s: %T", e.method, e.element) } // WriteElement is a one-stop shop to write the big endian representation of // any element which is to be serialized for storage on disk. The passed // io.Writer should be backed by an appropriately sized byte slice, or be able // to dynamically expand to accommodate additional data. func WriteElement(w io.Writer, element interface{}) error { switch e := element.(type) { case int64, uint64: if err := binary.Write(w, byteOrder, e); err != nil { return err } case uint32: if err := binary.Write(w, byteOrder, e); err != nil { return err } case int32: if err := binary.Write(w, byteOrder, e); err != nil { return err } case bool: if err := binary.Write(w, byteOrder, e); err != nil { return err } case lnwire.MilliSatoshi: if err := binary.Write(w, byteOrder, uint64(e)); err != nil { return err } case []byte: if err := wire.WriteVarBytes(w, 0, e); err != nil { return err } default: return UnknownElementType{"WriteElement", e} } return nil } // WriteElements is writes each element in the elements slice to the passed // io.Writer using WriteElement. func WriteElements(w io.Writer, elements ...interface{}) error { for _, element := range elements { err := WriteElement(w, element) if err != nil { return err } } return nil }