Go implementation

peoplecoin

Standard library only. Primitives, the state machine, and the nine operations — no networking, no video, no wallet yet.

state/ops.go

367 lines

1package state
2
3import (
4 "encoding/binary"
5 "errors"
6 "fmt"
7
8 "peoplecoin/params"
9 "peoplecoin/wire"
10)
11
12// Op is one operation in a block. Bytes is the canonical encoding stored
13// as the value in the block's tx trie; Message is the signing message,
14// which for address-keyed operations depends on the period of the block,
15// and doubles as the transaction hash, the key in the tx trie.
16type Op interface {
17 Opcode() uint8
18 Bytes() []byte
19 Message(period uint32) (Hash, error)
20 Signatures() [][64]byte
21}
22
23// TxHash returns the operation's key in the tx trie for a block in period:
24// its signing message. Signatures are not part of it, so the hash — and
25// with it the IDs of the operation's outputs — is known before signing and
26// cannot be altered by re-signing; the trie leaf, whose value is the full
27// operation, is what commits the block to the signatures.
28func TxHash(op Op, period uint32) (Hash, error) {
29 return op.Message(period)
30}
31
32var (
33 ErrEncoding = errors.New("state: malformed operation encoding")
34 ErrOpcode = errors.New("state: unknown opcode")
35)
36
37// ---------------------------------------------------------------------
38
39// Transfer spends coin UTXOs into new ones; the remainder is the fee.
40type Transfer struct {
41 Inputs []Address
42 Outputs []wire.TransferOutput
43 Sigs [][64]byte
44}
45
46func (*Transfer) Opcode() uint8 { return params.OpTransfer }
47func (t *Transfer) Signatures() [][64]byte { return t.Sigs }
48func (t *Transfer) Message(uint32) (Hash, error) { return wire.TransferMessage(t.Inputs, t.Outputs) }
49
50// Bytes: 0x00 ‖ ids(inputs) ‖ outputs ‖ uint8 nsigs ‖ sigs.
51func (t *Transfer) Bytes() []byte {
52 in, _ := wire.EncodeIDs(t.Inputs)
53 out, _ := wire.EncodeTransferOutputs(t.Outputs)
54 b := append([]byte{params.OpTransfer}, in...)
55 b = append(b, out...)
56 return appendSigs(b, t.Sigs)
57}
58
59// Mix re-keys tokens one to one.
60type Mix struct {
61 TokenID uint8
62 Inputs []Address
63 Outputs []wire.MixOutput
64 Sigs [][64]byte
65}
66
67func (*Mix) Opcode() uint8 { return params.OpMix }
68func (m *Mix) Signatures() [][64]byte { return m.Sigs }
69func (m *Mix) Message(uint32) (Hash, error) {
70 return wire.MixMessage(m.TokenID, m.Inputs, m.Outputs)
71}
72
73// Bytes: 0x01 ‖ token_id ‖ ids(inputs) ‖ outputs ‖ uint8 nsigs ‖ sigs.
74func (m *Mix) Bytes() []byte {
75 in, _ := wire.EncodeIDs(m.Inputs)
76 out, _ := wire.EncodeMixOutputs(m.Outputs)
77 b := append([]byte{params.OpMix, m.TokenID}, in...)
78 b = append(b, out...)
79 return appendSigs(b, m.Sigs)
80}
81
82// Vote turns an election token into a vote for a hidden validator.
83type Vote struct {
84 TokenUTXO Hash
85 Commit Hash
86 Sig [64]byte
87}
88
89func (*Vote) Opcode() uint8 { return params.OpVote }
90func (v *Vote) Signatures() [][64]byte { return [][64]byte{v.Sig} }
91func (v *Vote) Message(uint32) (Hash, error) { return wire.VoteMessage(v.TokenUTXO, v.Commit), nil }
92
93// Bytes: 0x02 ‖ token_utxo ‖ commit ‖ sig.
94func (v *Vote) Bytes() []byte {
95 b := append([]byte{params.OpVote}, v.TokenUTXO[:]...)
96 b = append(b, v.Commit[:]...)
97 return append(b, v.Sig[:]...)
98}
99
100// Register spends a registration token or InviteCost invite tokens for a
101// place in next period's registry.
102type Register struct {
103 TokenUTXOs []Address
104 Sig [64]byte
105}
106
107func (*Register) Opcode() uint8 { return params.OpRegister }
108func (r *Register) Signatures() [][64]byte { return [][64]byte{r.Sig} }
109func (r *Register) Message(uint32) (Hash, error) { return wire.RegisterMessage(r.TokenUTXOs) }
110
111// Bytes: 0x03 ‖ ids(token_utxos) ‖ sig.
112func (r *Register) Bytes() []byte {
113 in, _ := wire.EncodeIDs(r.TokenUTXOs)
114 b := append([]byte{params.OpRegister}, in...)
115 return append(b, r.Sig[:]...)
116}
117
118// Verify attests that the partner was there for the whole event.
119type Verify struct {
120 RegAddr Address
121 Sig [64]byte
122}
123
124func (*Verify) Opcode() uint8 { return params.OpVerify }
125func (v *Verify) Signatures() [][64]byte { return [][64]byte{v.Sig} }
126func (v *Verify) Message(period uint32) (Hash, error) {
127 return wire.VerifyMessage(period, v.RegAddr), nil
128}
129
130// Bytes: 0x04 ‖ reg_addr ‖ sig.
131func (v *Verify) Bytes() []byte {
132 return append(append([]byte{params.OpVerify}, v.RegAddr[:]...), v.Sig[:]...)
133}
134
135// Verified collects the pass once both flags are set.
136type Verified struct {
137 RegAddr Address
138 Sig [64]byte
139}
140
141func (*Verified) Opcode() uint8 { return params.OpVerified }
142func (v *Verified) Signatures() [][64]byte { return [][64]byte{v.Sig} }
143func (v *Verified) Message(period uint32) (Hash, error) {
144 return wire.VerifiedMessage(period, v.RegAddr), nil
145}
146
147// Bytes: 0x05 ‖ reg_addr ‖ sig.
148func (v *Verified) Bytes() []byte {
149 return append(append([]byte{params.OpVerified}, v.RegAddr[:]...), v.Sig[:]...)
150}
151
152// Commit commits an RNG entry to a number.
153type Commit struct {
154 RngAddr Address
155 Commit Hash
156 Sig [64]byte
157}
158
159func (*Commit) Opcode() uint8 { return params.OpCommit }
160func (c *Commit) Signatures() [][64]byte { return [][64]byte{c.Sig} }
161func (c *Commit) Message(period uint32) (Hash, error) {
162 return wire.CommitMessage(period, c.RngAddr, c.Commit), nil
163}
164
165// Bytes: 0x06 ‖ rng_addr ‖ commit ‖ sig.
166func (c *Commit) Bytes() []byte {
167 b := append([]byte{params.OpCommit}, c.RngAddr[:]...)
168 b = append(b, c.Commit[:]...)
169 return append(b, c.Sig[:]...)
170}
171
172// Reveal opens the commit, casts a vote and collects the UBI.
173type Reveal struct {
174 RngAddr Address
175 Preimage Hash
176 Sig [64]byte
177}
178
179func (*Reveal) Opcode() uint8 { return params.OpReveal }
180func (r *Reveal) Signatures() [][64]byte { return [][64]byte{r.Sig} }
181func (r *Reveal) Message(period uint32) (Hash, error) {
182 return wire.RevealMessage(period, r.RngAddr, r.Preimage), nil
183}
184
185// Bytes: 0x07 ‖ rng_addr ‖ preimage ‖ sig.
186func (r *Reveal) Bytes() []byte {
187 b := append([]byte{params.OpReveal}, r.RngAddr[:]...)
188 b = append(b, r.Preimage[:]...)
189 return append(b, r.Sig[:]...)
190}
191
192// Prune deletes a coin entry that rent has consumed. It is unsigned; only
193// the block's validator includes it, which any block trivially satisfies.
194type Prune struct {
195 UTXO Hash
196}
197
198func (*Prune) Opcode() uint8 { return params.OpPrune }
199func (*Prune) Signatures() [][64]byte { return nil }
200func (p *Prune) Message(uint32) (Hash, error) { return wire.PruneMessage(p.UTXO), nil }
201
202// Bytes: 0xFF ‖ utxo_id.
203func (p *Prune) Bytes() []byte { return append([]byte{params.OpPrune}, p.UTXO[:]...) }
204
205// ---------------------------------------------------------------------
206// Decoding
207
208func appendSigs(b []byte, sigs [][64]byte) []byte {
209 b = append(b, uint8(len(sigs)))
210 for i := range sigs {
211 b = append(b, sigs[i][:]...)
212 }
213 return b
214}
215
216type reader struct {
217 b []byte
218 err error
219}
220
221func (r *reader) u8() uint8 {
222 if r.err != nil || len(r.b) < 1 {
223 r.err = ErrEncoding
224 return 0
225 }
226 v := r.b[0]
227 r.b = r.b[1:]
228 return v
229}
230
231func (r *reader) u32() uint32 {
232 if r.err != nil || len(r.b) < 4 {
233 r.err = ErrEncoding
234 return 0
235 }
236 v := binary.BigEndian.Uint32(r.b)
237 r.b = r.b[4:]
238 return v
239}
240
241func (r *reader) u64() uint64 {
242 if r.err != nil || len(r.b) < 8 {
243 r.err = ErrEncoding
244 return 0
245 }
246 v := binary.BigEndian.Uint64(r.b)
247 r.b = r.b[8:]
248 return v
249}
250
251func (r *reader) h32() (h [32]byte) {
252 if r.err != nil || len(r.b) < 32 {
253 r.err = ErrEncoding
254 return
255 }
256 copy(h[:], r.b)
257 r.b = r.b[32:]
258 return
259}
260
261func (r *reader) sig() (s [64]byte) {
262 if r.err != nil || len(r.b) < 64 {
263 r.err = ErrEncoding
264 return
265 }
266 copy(s[:], r.b)
267 r.b = r.b[64:]
268 return
269}
270
271func (r *reader) ids() []Address {
272 n := int(r.u8())
273 out := make([]Address, 0, n)
274 for i := 0; i < n && r.err == nil; i++ {
275 out = append(out, r.h32())
276 }
277 return out
278}
279
280func (r *reader) sigs() [][64]byte {
281 n := int(r.u8())
282 out := make([][64]byte, 0, n)
283 for i := 0; i < n && r.err == nil; i++ {
284 out = append(out, r.sig())
285 }
286 return out
287}
288
289func (r *reader) done() error {
290 if r.err != nil {
291 return r.err
292 }
293 if len(r.b) != 0 {
294 return ErrEncoding
295 }
296 return nil
297}
298
299// DecodeOp parses a canonical operation encoding. Re-encoding the result
300// yields the input, so the tx trie value is unambiguous.
301func DecodeOp(b []byte) (Op, error) {
302 if len(b) < 1 {
303 return nil, ErrEncoding
304 }
305 r := &reader{b: b[1:]}
306 var op Op
307 switch b[0] {
308 case params.OpTransfer:
309 t := &Transfer{Inputs: r.ids()}
310 n := int(r.u8())
311 for i := 0; i < n && r.err == nil; i++ {
312 o := wire.TransferOutput{Amount: r.u64()}
313 o.Owners = r.ids()
314 o.Threshold = r.u8()
315 t.Outputs = append(t.Outputs, o)
316 }
317 t.Sigs = r.sigs()
318 op = t
319 case params.OpMix:
320 m := &Mix{TokenID: r.u8()}
321 m.Inputs = r.ids()
322 n := int(r.u8())
323 for i := 0; i < n && r.err == nil; i++ {
324 o := wire.MixOutput{MixCount: r.u32()}
325 o.Owner = r.h32()
326 m.Outputs = append(m.Outputs, o)
327 }
328 m.Sigs = r.sigs()
329 op = m
330 case params.OpVote:
331 op = &Vote{TokenUTXO: r.h32(), Commit: r.h32(), Sig: r.sig()}
332 case params.OpRegister:
333 op = &Register{TokenUTXOs: r.ids(), Sig: r.sig()}
334 case params.OpVerify:
335 op = &Verify{RegAddr: r.h32(), Sig: r.sig()}
336 case params.OpVerified:
337 op = &Verified{RegAddr: r.h32(), Sig: r.sig()}
338 case params.OpCommit:
339 op = &Commit{RngAddr: r.h32(), Commit: r.h32(), Sig: r.sig()}
340 case params.OpReveal:
341 op = &Reveal{RngAddr: r.h32(), Preimage: r.h32(), Sig: r.sig()}
342 case params.OpPrune:
343 op = &Prune{UTXO: r.h32()}
344 default:
345 return nil, fmt.Errorf("%w: 0x%02x", ErrOpcode, b[0])
346 }
347 if err := r.done(); err != nil {
348 return nil, err
349 }
350 return op, nil
351}
352
353// allowedPhase reports whether the opcode may appear in a block in phase.
354func allowedPhase(opcode uint8, phase uint64) bool {
355 switch opcode {
356 case params.OpTransfer, params.OpPrune:
357 return true
358 case params.OpMix, params.OpVote, params.OpRegister, params.OpVerified, params.OpCommit:
359 return phase <= 1
360 case params.OpVerify:
361 return phase == 0
362 case params.OpReveal:
363 return phase == 2
364 }
365 return false
366}