state/ops.go
367 lines
1package state23import (4"encoding/binary"5"errors"6"fmt"78"peoplecoin/params"9"peoplecoin/wire"10)1112// Op is one operation in a block. Bytes is the canonical encoding stored13// 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 {17Opcode() uint818Bytes() []byte19Message(period uint32) (Hash, error)20Signatures() [][64]byte21}2223// 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 — and25// with it the IDs of the operation's outputs — is known before signing and26// cannot be altered by re-signing; the trie leaf, whose value is the full27// operation, is what commits the block to the signatures.28func TxHash(op Op, period uint32) (Hash, error) {29return op.Message(period)30}3132var (33ErrEncoding = errors.New("state: malformed operation encoding")34ErrOpcode = errors.New("state: unknown opcode")35)3637// ---------------------------------------------------------------------3839// Transfer spends coin UTXOs into new ones; the remainder is the fee.40type Transfer struct {41Inputs []Address42Outputs []wire.TransferOutput43Sigs [][64]byte44}4546func (*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) }4950// Bytes: 0x00 ‖ ids(inputs) ‖ outputs ‖ uint8 nsigs ‖ sigs.51func (t *Transfer) Bytes() []byte {52in, _ := wire.EncodeIDs(t.Inputs)53out, _ := wire.EncodeTransferOutputs(t.Outputs)54b := append([]byte{params.OpTransfer}, in...)55b = append(b, out...)56return appendSigs(b, t.Sigs)57}5859// Mix re-keys tokens one to one.60type Mix struct {61TokenID uint862Inputs []Address63Outputs []wire.MixOutput64Sigs [][64]byte65}6667func (*Mix) Opcode() uint8 { return params.OpMix }68func (m *Mix) Signatures() [][64]byte { return m.Sigs }69func (m *Mix) Message(uint32) (Hash, error) {70return wire.MixMessage(m.TokenID, m.Inputs, m.Outputs)71}7273// Bytes: 0x01 ‖ token_id ‖ ids(inputs) ‖ outputs ‖ uint8 nsigs ‖ sigs.74func (m *Mix) Bytes() []byte {75in, _ := wire.EncodeIDs(m.Inputs)76out, _ := wire.EncodeMixOutputs(m.Outputs)77b := append([]byte{params.OpMix, m.TokenID}, in...)78b = append(b, out...)79return appendSigs(b, m.Sigs)80}8182// Vote turns an election token into a vote for a hidden validator.83type Vote struct {84TokenUTXO Hash85Commit Hash86Sig [64]byte87}8889func (*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 }9293// Bytes: 0x02 ‖ token_utxo ‖ commit ‖ sig.94func (v *Vote) Bytes() []byte {95b := append([]byte{params.OpVote}, v.TokenUTXO[:]...)96b = append(b, v.Commit[:]...)97return append(b, v.Sig[:]...)98}99100// Register spends a registration token or InviteCost invite tokens for a101// place in next period's registry.102type Register struct {103TokenUTXOs []Address104Sig [64]byte105}106107func (*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) }110111// Bytes: 0x03 ‖ ids(token_utxos) ‖ sig.112func (r *Register) Bytes() []byte {113in, _ := wire.EncodeIDs(r.TokenUTXOs)114b := append([]byte{params.OpRegister}, in...)115return append(b, r.Sig[:]...)116}117118// Verify attests that the partner was there for the whole event.119type Verify struct {120RegAddr Address121Sig [64]byte122}123124func (*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) {127return wire.VerifyMessage(period, v.RegAddr), nil128}129130// Bytes: 0x04 ‖ reg_addr ‖ sig.131func (v *Verify) Bytes() []byte {132return append(append([]byte{params.OpVerify}, v.RegAddr[:]...), v.Sig[:]...)133}134135// Verified collects the pass once both flags are set.136type Verified struct {137RegAddr Address138Sig [64]byte139}140141func (*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) {144return wire.VerifiedMessage(period, v.RegAddr), nil145}146147// Bytes: 0x05 ‖ reg_addr ‖ sig.148func (v *Verified) Bytes() []byte {149return append(append([]byte{params.OpVerified}, v.RegAddr[:]...), v.Sig[:]...)150}151152// Commit commits an RNG entry to a number.153type Commit struct {154RngAddr Address155Commit Hash156Sig [64]byte157}158159func (*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) {162return wire.CommitMessage(period, c.RngAddr, c.Commit), nil163}164165// Bytes: 0x06 ‖ rng_addr ‖ commit ‖ sig.166func (c *Commit) Bytes() []byte {167b := append([]byte{params.OpCommit}, c.RngAddr[:]...)168b = append(b, c.Commit[:]...)169return append(b, c.Sig[:]...)170}171172// Reveal opens the commit, casts a vote and collects the UBI.173type Reveal struct {174RngAddr Address175Preimage Hash176Sig [64]byte177}178179func (*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) {182return wire.RevealMessage(period, r.RngAddr, r.Preimage), nil183}184185// Bytes: 0x07 ‖ rng_addr ‖ preimage ‖ sig.186func (r *Reveal) Bytes() []byte {187b := append([]byte{params.OpReveal}, r.RngAddr[:]...)188b = append(b, r.Preimage[:]...)189return append(b, r.Sig[:]...)190}191192// Prune deletes a coin entry that rent has consumed. It is unsigned; only193// the block's validator includes it, which any block trivially satisfies.194type Prune struct {195UTXO Hash196}197198func (*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 }201202// Bytes: 0xFF ‖ utxo_id.203func (p *Prune) Bytes() []byte { return append([]byte{params.OpPrune}, p.UTXO[:]...) }204205// ---------------------------------------------------------------------206// Decoding207208func appendSigs(b []byte, sigs [][64]byte) []byte {209b = append(b, uint8(len(sigs)))210for i := range sigs {211b = append(b, sigs[i][:]...)212}213return b214}215216type reader struct {217b []byte218err error219}220221func (r *reader) u8() uint8 {222if r.err != nil || len(r.b) < 1 {223r.err = ErrEncoding224return 0225}226v := r.b[0]227r.b = r.b[1:]228return v229}230231func (r *reader) u32() uint32 {232if r.err != nil || len(r.b) < 4 {233r.err = ErrEncoding234return 0235}236v := binary.BigEndian.Uint32(r.b)237r.b = r.b[4:]238return v239}240241func (r *reader) u64() uint64 {242if r.err != nil || len(r.b) < 8 {243r.err = ErrEncoding244return 0245}246v := binary.BigEndian.Uint64(r.b)247r.b = r.b[8:]248return v249}250251func (r *reader) h32() (h [32]byte) {252if r.err != nil || len(r.b) < 32 {253r.err = ErrEncoding254return255}256copy(h[:], r.b)257r.b = r.b[32:]258return259}260261func (r *reader) sig() (s [64]byte) {262if r.err != nil || len(r.b) < 64 {263r.err = ErrEncoding264return265}266copy(s[:], r.b)267r.b = r.b[64:]268return269}270271func (r *reader) ids() []Address {272n := int(r.u8())273out := make([]Address, 0, n)274for i := 0; i < n && r.err == nil; i++ {275out = append(out, r.h32())276}277return out278}279280func (r *reader) sigs() [][64]byte {281n := int(r.u8())282out := make([][64]byte, 0, n)283for i := 0; i < n && r.err == nil; i++ {284out = append(out, r.sig())285}286return out287}288289func (r *reader) done() error {290if r.err != nil {291return r.err292}293if len(r.b) != 0 {294return ErrEncoding295}296return nil297}298299// DecodeOp parses a canonical operation encoding. Re-encoding the result300// yields the input, so the tx trie value is unambiguous.301func DecodeOp(b []byte) (Op, error) {302if len(b) < 1 {303return nil, ErrEncoding304}305r := &reader{b: b[1:]}306var op Op307switch b[0] {308case params.OpTransfer:309t := &Transfer{Inputs: r.ids()}310n := int(r.u8())311for i := 0; i < n && r.err == nil; i++ {312o := wire.TransferOutput{Amount: r.u64()}313o.Owners = r.ids()314o.Threshold = r.u8()315t.Outputs = append(t.Outputs, o)316}317t.Sigs = r.sigs()318op = t319case params.OpMix:320m := &Mix{TokenID: r.u8()}321m.Inputs = r.ids()322n := int(r.u8())323for i := 0; i < n && r.err == nil; i++ {324o := wire.MixOutput{MixCount: r.u32()}325o.Owner = r.h32()326m.Outputs = append(m.Outputs, o)327}328m.Sigs = r.sigs()329op = m330case params.OpVote:331op = &Vote{TokenUTXO: r.h32(), Commit: r.h32(), Sig: r.sig()}332case params.OpRegister:333op = &Register{TokenUTXOs: r.ids(), Sig: r.sig()}334case params.OpVerify:335op = &Verify{RegAddr: r.h32(), Sig: r.sig()}336case params.OpVerified:337op = &Verified{RegAddr: r.h32(), Sig: r.sig()}338case params.OpCommit:339op = &Commit{RngAddr: r.h32(), Commit: r.h32(), Sig: r.sig()}340case params.OpReveal:341op = &Reveal{RngAddr: r.h32(), Preimage: r.h32(), Sig: r.sig()}342case params.OpPrune:343op = &Prune{UTXO: r.h32()}344default:345return nil, fmt.Errorf("%w: 0x%02x", ErrOpcode, b[0])346}347if err := r.done(); err != nil {348return nil, err349}350return op, nil351}352353// allowedPhase reports whether the opcode may appear in a block in phase.354func allowedPhase(opcode uint8, phase uint64) bool {355switch opcode {356case params.OpTransfer, params.OpPrune:357return true358case params.OpMix, params.OpVote, params.OpRegister, params.OpVerified, params.OpCommit:359return phase <= 1360case params.OpVerify:361return phase == 0362case params.OpReveal:363return phase == 2364}365return false366}