eventbin.go raw

   1  package store
   2  
   3  import (
   4  	"encoding/binary"
   5  	"errors"
   6  
   7  	"git.smesh.lol/torly/pkg/nostr"
   8  )
   9  
  10  // Event encoding in the WAL:
  11  //
  12  //	version(1) | kind(2) | created_at(8) | pubkey(32) | id(32) | sig(64)
  13  //	tag count(2) | per tag: field count(2), per field: len(4) + bytes
  14  //	content len(4) + bytes
  15  //
  16  // The encoding is compact and trivially decodable; the JSON wire form is
  17  // regenerated from it when an event is served.
  18  const eventVersion = 1
  19  
  20  var errBadEventEncoding = errors.New("store: malformed event record")
  21  
  22  func appendU16(dst []byte, v uint16) []byte { return append(dst, byte(v>>8), byte(v)) }
  23  func appendU32(dst []byte, v uint32) []byte {
  24  	return append(dst, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  25  }
  26  func appendU64(dst []byte, v uint64) []byte {
  27  	return append(dst, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32),
  28  		byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
  29  }
  30  
  31  func encodeEvent(ev *nostr.Event) []byte {
  32  	size := 1 + 2 + 8 + 32 + 32 + 64 + 2 + 4 + len(ev.Content)
  33  	for _, tag := range ev.Tags {
  34  		size += 2
  35  		for _, field := range tag {
  36  			size += 4 + len(field)
  37  		}
  38  	}
  39  	out := make([]byte, 0, size)
  40  	out = append(out, eventVersion)
  41  	out = appendU16(out, uint16(ev.Kind))
  42  	out = appendU64(out, uint64(ev.CreatedAt))
  43  	out = append(out, ev.PubKey[:]...)
  44  	out = append(out, ev.ID[:]...)
  45  	out = append(out, ev.Sig[:]...)
  46  	out = appendU16(out, uint16(len(ev.Tags)))
  47  	for _, tag := range ev.Tags {
  48  		out = appendU16(out, uint16(len(tag)))
  49  		for _, field := range tag {
  50  			out = appendU32(out, uint32(len(field)))
  51  			out = append(out, field...)
  52  		}
  53  	}
  54  	out = appendU32(out, uint32(len(ev.Content)))
  55  	out = append(out, ev.Content...)
  56  	return out
  57  }
  58  
  59  type decoder struct {
  60  	data []byte
  61  	pos  int
  62  }
  63  
  64  func (d *decoder) u8() (byte, bool) {
  65  	if d.pos+1 > len(d.data) {
  66  		return 0, false
  67  	}
  68  	v := d.data[d.pos]
  69  	d.pos++
  70  	return v, true
  71  }
  72  
  73  func (d *decoder) u16() (uint16, bool) {
  74  	if d.pos+2 > len(d.data) {
  75  		return 0, false
  76  	}
  77  	v := binary.BigEndian.Uint16(d.data[d.pos:])
  78  	d.pos += 2
  79  	return v, true
  80  }
  81  
  82  func (d *decoder) u32() (uint32, bool) {
  83  	if d.pos+4 > len(d.data) {
  84  		return 0, false
  85  	}
  86  	v := binary.BigEndian.Uint32(d.data[d.pos:])
  87  	d.pos += 4
  88  	return v, true
  89  }
  90  
  91  func (d *decoder) u64() (uint64, bool) {
  92  	if d.pos+8 > len(d.data) {
  93  		return 0, false
  94  	}
  95  	v := binary.BigEndian.Uint64(d.data[d.pos:])
  96  	d.pos += 8
  97  	return v, true
  98  }
  99  
 100  func (d *decoder) bytes(n int) ([]byte, bool) {
 101  	if n < 0 || d.pos+n > len(d.data) {
 102  		return nil, false
 103  	}
 104  	v := d.data[d.pos : d.pos+n]
 105  	d.pos += n
 106  	return v, true
 107  }
 108  
 109  func decodeEvent(data []byte) (*nostr.Event, error) {
 110  	d := &decoder{data: data}
 111  	ver, ok := d.u8()
 112  	if !ok || ver != eventVersion {
 113  		return nil, errBadEventEncoding
 114  	}
 115  	kind, ok := d.u16()
 116  	if !ok {
 117  		return nil, errBadEventEncoding
 118  	}
 119  	created, ok := d.u64()
 120  	if !ok {
 121  		return nil, errBadEventEncoding
 122  	}
 123  	pub, ok := d.bytes(32)
 124  	if !ok {
 125  		return nil, errBadEventEncoding
 126  	}
 127  	id, ok := d.bytes(32)
 128  	if !ok {
 129  		return nil, errBadEventEncoding
 130  	}
 131  	sig, ok := d.bytes(64)
 132  	if !ok {
 133  		return nil, errBadEventEncoding
 134  	}
 135  	ev := &nostr.Event{
 136  		CreatedAt: int64(created),
 137  		Kind:      int(kind),
 138  	}
 139  	copy(ev.PubKey[:], pub)
 140  	copy(ev.ID[:], id)
 141  	copy(ev.Sig[:], sig)
 142  
 143  	tagN, ok := d.u16()
 144  	if !ok {
 145  		return nil, errBadEventEncoding
 146  	}
 147  	ev.Tags = make(nostr.Tags, 0, tagN)
 148  	for i := 0; i < int(tagN); i++ {
 149  		fieldN, ok := d.u16()
 150  		if !ok {
 151  			return nil, errBadEventEncoding
 152  		}
 153  		tag := make(nostr.Tag, 0, fieldN)
 154  		for j := 0; j < int(fieldN); j++ {
 155  			n, ok := d.u32()
 156  			if !ok || n > 1<<20 {
 157  				return nil, errBadEventEncoding
 158  			}
 159  			b, ok := d.bytes(int(n))
 160  			if !ok {
 161  				return nil, errBadEventEncoding
 162  			}
 163  			tag = append(tag, string(b))
 164  		}
 165  		ev.Tags = append(ev.Tags, tag)
 166  	}
 167  	clen, ok := d.u32()
 168  	if !ok || clen > 16<<20 {
 169  		return nil, errBadEventEncoding
 170  	}
 171  	content, ok := d.bytes(int(clen))
 172  	if !ok {
 173  		return nil, errBadEventEncoding
 174  	}
 175  	ev.Content = string(content)
 176  	if d.pos != len(d.data) {
 177  		return nil, errBadEventEncoding
 178  	}
 179  	return ev, nil
 180  }
 181