solana-go/nativetypes.go

289 lines
5.2 KiB
Go

package solana
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"strconv"
"github.com/lunixbochs/struc"
"github.com/mr-tron/base58"
)
type Padding []byte
type Hash PublicKey
///
type Signature [64]byte
func SignatureFromBase58(in string) (out Signature, err error) {
val, err := base58.Decode(in)
if err != nil {
return
}
if len(val) != 64 {
err = fmt.Errorf("invalid length, expected 64, got %d", len(val))
return
}
copy(out[:], val)
return
}
func (p Signature) MarshalJSON() ([]byte, error) {
return json.Marshal(base58.Encode(p[:]))
}
func (p *Signature) UnmarshalJSON(data []byte) (err error) {
var s string
err = json.Unmarshal(data, &s)
if err != nil {
return
}
dat, err := base58.Decode(s)
if err != nil {
return err
}
if len(dat) != 64 {
return errors.New("invalid data length for public key")
}
target := Signature{}
copy(target[:], dat)
*p = target
return
}
func (p Signature) String() string {
return base58.Encode(p[:])
}
///
type PublicKey [32]byte
func MustPublicKeyFromBase58(in string) PublicKey {
out, _ := PublicKeyFromBase58(in)
return out
}
func PublicKeyFromBase58(in string) (out PublicKey, err error) {
val, err := base58.Decode(in)
if err != nil {
return
}
if len(val) != 32 {
err = fmt.Errorf("invalid length, expected 32, got %d", len(val))
return
}
copy(out[:], val)
return
}
func (p PublicKey) MarshalJSON() ([]byte, error) {
return json.Marshal(base58.Encode(p[:]))
}
func (p *PublicKey) UnmarshalJSON(data []byte) (err error) {
var s string
err = json.Unmarshal(data, &s)
if err != nil {
return
}
dat, err := base58.Decode(s)
if err != nil {
return err
}
if len(dat) != 32 {
return errors.New("invalid data length for public key")
}
target := PublicKey{}
copy(target[:], dat)
*p = target
return
}
func (p PublicKey) String() string {
return base58.Encode(p[:])
}
///
type Base58 []byte
func (t Base58) MarshalJSON() ([]byte, error) {
return json.Marshal(base58.Encode(t))
}
func (t *Base58) UnmarshalJSON(data []byte) (err error) {
var s string
err = json.Unmarshal(data, &s)
if err != nil {
return
}
*t, err = base58.Decode(s)
return
}
func (t Base58) String() string {
return base58.Encode(t)
}
///
type U64 uint64
func (i U64) MarshalJSON() (data []byte, err error) {
if i > 0xffffffff {
encodedInt, err := json.Marshal(uint64(i))
if err != nil {
return nil, err
}
data = append([]byte{'"'}, encodedInt...)
data = append(data, '"')
return data, nil
}
return json.Marshal(uint64(i))
}
func (i *U64) UnmarshalJSON(data []byte) error {
if len(data) == 0 {
return errors.New("empty value")
}
if data[0] == '"' {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
val, err := strconv.ParseUint(s, 10, 64)
if err != nil {
return err
}
*i = U64(val)
return nil
}
var v uint64
if err := json.Unmarshal(data, &v); err != nil {
return err
}
*i = U64(v)
return nil
}
///
type ByteWrapper struct {
io.Reader
}
func (w *ByteWrapper) ReadByte() (byte, error) {
var b [1]byte
_, err := w.Read(b[:])
return b[0], err
}
/// Varuint16
type Varuint16 uint16
func (v Varuint16) Pack(buf []byte, opt *struc.Options) (int, error) {
x := uint64(v)
i := 0
for x >= 0x80 {
buf[i] = byte(x) | 0x80
x >>= 7
i++
}
buf[i] = byte(x)
return i + 1, nil
// JAVASCRIPT
// let rem_len = len;
// for (;;) {
// let elem = rem_len & 0x7f;
// rem_len >>= 7;
// if (rem_len == 0) {
// bytes.push(elem);
// break;
// } else {
// elem |= 0x80;
// bytes.push(elem);
// }
// }
// RUST
// // Pass a non-zero value to serialize_tuple() so that serde_json will
// // generate an open bracket.
// let mut seq = serializer.serialize_tuple(1)?;
// let mut rem_len = self.0;
// loop {
// let mut elem = (rem_len & 0x7f) as u8;
// rem_len >>= 7;
// if rem_len == 0 {
// seq.serialize_element(&elem)?;
// break;
// } else {
// elem |= 0x80;
// seq.serialize_element(&elem)?;
// }
// }
// seq.end()
}
func (v *Varuint16) Unpack(r io.Reader, length int, opt *struc.Options) error {
res, err := readVaruint16(&ByteWrapper{r})
if err != nil {
return err
}
*v = Varuint16(res)
return nil
}
func (v *Varuint16) Size(opt *struc.Options) int {
// TODO: fix the `Size`, which doesn't reflect.. need to Pack, and return the size here?
var buf [8]byte
return binary.PutUvarint(buf[:], uint64(*v))
}
func (v *Varuint16) String() string {
return strconv.FormatUint(uint64(*v), 10)
}
var shortVecOverflow = errors.New("short_vec: varint overflows a 16-bit integer")
func readVaruint16(r io.ByteReader) (uint64, error) {
// This was identified https://groups.google.com/g/golang-announce/c/NyPIaucMgXo/m/GdsyQP6QAAAJ?pli=1
// after I copied it here.. and I think we're using the EXACT same construct.. and in our case,
// we don't want to read more than 3 bytes.
// FIXME!!!!
var x uint64
var s uint
for i := 0; ; i++ {
b, err := r.ReadByte()
if err != nil {
return x, err
}
if b < 0x80 {
if i > 4 || i == 4 && b > 1 {
return x, shortVecOverflow
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
s += 7
}
}