From 399f1aba4d2de66d7bb88b2291b3316113e81c52 Mon Sep 17 00:00:00 2001 From: Ethan Reesor Date: Sat, 23 Sep 2023 17:48:52 +0000 Subject: [PATCH] Fix synthetic message hash [#3406] Closes #3406. Creates a new synthetic message type with a fixed hash implementation. Changelog: fix --- internal/core/execute/multi/multi_test.go | 34 ++ internal/core/execute/v2/block/block_begin.go | 15 +- internal/core/execute/v2/block/block_end.go | 13 +- .../core/execute/v2/block/exec_process.go | 13 + internal/core/execute/v2/block/msg_common.go | 14 +- .../core/execute/v2/block/msg_synthetic.go | 26 +- .../execute/v2/block/msg_synthetic_test.go | 2 +- pkg/types/messaging/enums.yml | 9 +- pkg/types/messaging/enums_gen.go | 21 +- pkg/types/messaging/messages.yml | 21 +- pkg/types/messaging/synthetic.go | 23 ++ pkg/types/messaging/types.go | 24 +- pkg/types/messaging/types_gen.go | 301 ++++++++++++++++++ pkg/types/messaging/unions_gen.go | 10 + protocol/signature_test.go | 2 +- protocol/version.go | 2 +- test/simulator/consensus/node.go | 3 + 17 files changed, 500 insertions(+), 33 deletions(-) create mode 100644 pkg/types/messaging/synthetic.go diff --git a/internal/core/execute/multi/multi_test.go b/internal/core/execute/multi/multi_test.go index 07f0de2bb..65c5d367e 100644 --- a/internal/core/execute/multi/multi_test.go +++ b/internal/core/execute/multi/multi_test.go @@ -7,6 +7,7 @@ package execute_test import ( + "fmt" "math/big" "testing" @@ -71,6 +72,7 @@ func TestVersionSwitch(t *testing.T) { require.NotEmpty(t, sim.QueryAccount(alice, nil).Pending.Records) // Update to v1-halt + fmt.Println("Switching to v1 halt") sim.SubmitTxnSuccessfully(MustBuild(t, build.Transaction().For(DnUrl()). ActivateProtocolVersion(ExecutorVersionV1Halt). @@ -124,7 +126,11 @@ func TestVersionSwitch(t *testing.T) { require.EqualError(t, st.AsError(), "user messages are not being accepted: an upgrade is in progress") + // Wait for everything to settle + sim.StepN(20) + // Update to v2 + fmt.Println("Switching to v2") st = sim.SubmitTxnSuccessfully(MustBuild(t, build.Transaction().For(DnUrl()). ActivateProtocolVersion(ExecutorVersionV2). @@ -157,4 +163,32 @@ func TestVersionSwitch(t *testing.T) { sim.StepUntil( Txn(p.TxID).IsPending()) + + // Update to v2 baikonur + fmt.Println("Switching to v2 baikonur") + st = sim.SubmitTxnSuccessfully(MustBuild(t, + build.Transaction().For(DnUrl()). + ActivateProtocolVersion(ExecutorVersionV2Baikonur). + SignWith(DnUrl(), Operators, "1").Version(1).Timestamp(×tamp).Signer(sim.SignWithNode(Directory, 0)))) + + sim.StepUntil( + Txn(st.TxID).Succeeds()) + + // Give it a few blocks for the anchor to propagate + sim.StepN(10) + + require.Equal(t, ExecutorVersionV2Baikonur, GetAccount[*SystemLedger](t, sim.Database(Directory), DnUrl().JoinPath(Ledger)).ExecutorVersion) + require.Equal(t, ExecutorVersionV2Baikonur, GetAccount[*SystemLedger](t, sim.Database("BVN0"), PartitionUrl("BVN0").JoinPath(Ledger)).ExecutorVersion) + require.Equal(t, ExecutorVersionV2Baikonur, GetAccount[*SystemLedger](t, sim.Database("BVN1"), PartitionUrl("BVN1").JoinPath(Ledger)).ExecutorVersion) + require.Equal(t, ExecutorVersionV2Baikonur, GetAccount[*SystemLedger](t, sim.Database("BVN2"), PartitionUrl("BVN2").JoinPath(Ledger)).ExecutorVersion) + + // Trigger a synthetic transaction + st = sim.SubmitTxnSuccessfully(MustBuild(t, + build.Transaction().For(alice, "tokens"). + BurnTokens(1, 0). + SignWith(alice, "book", "1").Version(1).Timestamp(×tamp).PrivateKey(aliceKey))) + + sim.StepUntil( + Txn(st.TxID).Succeeds(), + Txn(st.TxID).Produced().Capture(&st).Succeeds()) } diff --git a/internal/core/execute/v2/block/block_begin.go b/internal/core/execute/v2/block/block_begin.go index 7a4d3803d..380f0860b 100644 --- a/internal/core/execute/v2/block/block_begin.go +++ b/internal/core/execute/v2/block/block_begin.go @@ -479,12 +479,21 @@ func (x *Executor) sendSyntheticTransactionsForBlock(batch *database.Batch, isLe } messages := []messaging.Message{ - &messaging.SyntheticMessage{ + &messaging.BadSyntheticMessage{ Message: seq, Proof: receipt, Signature: keySig, }, } + if x.globals.Active.ExecutorVersion.V2BaikonurEnabled() { + messages = []messaging.Message{ + &messaging.SyntheticMessage{ + Message: seq, + Proof: receipt, + Signature: keySig, + }, + } + } // Send the transaction along with the signature request/authority // signature @@ -519,7 +528,7 @@ func (x *Executor) sendBlockAnchor(block *Block, anchor protocol.AnchorBody, seq return nil } - // If we're on the DN, the last block updated to v2, and the destination is + // If we're on the DN, the last block updated to v2, and the destination is // a BVN, then we must send out the anchor as a v1 anchor since the BVNs // will still be running v1 destPartUrl := protocol.PartitionUrl(destPart) @@ -580,7 +589,7 @@ func didUpdateToV2(anchor protocol.AnchorBody) bool { for _, update := range dir.Updates { update, ok := update.Body.(*protocol.ActivateProtocolVersion) - if ok && update.Version.V2Enabled() { + if ok && update.Version == protocol.ExecutorVersionV2 { return true } } diff --git a/internal/core/execute/v2/block/block_end.go b/internal/core/execute/v2/block/block_end.go index ae0744f04..8b6052581 100644 --- a/internal/core/execute/v2/block/block_end.go +++ b/internal/core/execute/v2/block/block_end.go @@ -397,7 +397,7 @@ func (x *Executor) requestMissingTransactionsFromPartition(ctx context.Context, Anchor: seq, Signature: keySig, } - } else { + } else if x.globals.Active.ExecutorVersion.V2BaikonurEnabled() { msg = &messaging.SyntheticMessage{ Message: seq, Signature: keySig, @@ -408,6 +408,17 @@ func (x *Executor) requestMissingTransactionsFromPartition(ctx context.Context, }, }, } + } else { + msg = &messaging.BadSyntheticMessage{ + Message: seq, + Signature: keySig, + Proof: &protocol.AnnotatedReceipt{ + Receipt: resp.SourceReceipt, + Anchor: &protocol.AnchorMetadata{ + Account: protocol.DnUrl(), + }, + }, + } } err = dispatcher.Submit(ctx, dest, &messaging.Envelope{Messages: []messaging.Message{msg}}) diff --git a/internal/core/execute/v2/block/exec_process.go b/internal/core/execute/v2/block/exec_process.go index bff90d6f2..d4593119a 100644 --- a/internal/core/execute/v2/block/exec_process.go +++ b/internal/core/execute/v2/block/exec_process.go @@ -147,6 +147,19 @@ func (d *bundle) process() ([]*protocol.TransactionStatus, error) { fn = b.Executor.logger.Info kv = append(kv, "module", "anchoring") + case *messaging.BadSyntheticMessage: + if seq, ok := msg.Message.(*messaging.SequencedMessage); ok { + kv = append(kv, "inner-type", seq.Message.ID()) + kv = append(kv, "source", seq.Source) + kv = append(kv, "dest", seq.Destination) + kv = append(kv, "seq", seq.Number) + + switch msg := seq.Message.(type) { + case *messaging.TransactionMessage: + kv = append(kv, "txn-type", msg.Transaction.Body.Type()) + } + } + case *messaging.SyntheticMessage: if seq, ok := msg.Message.(*messaging.SequencedMessage); ok { kv = append(kv, "inner-type", seq.Message.ID()) diff --git a/internal/core/execute/v2/block/msg_common.go b/internal/core/execute/v2/block/msg_common.go index fa4efc784..79e3a3d1d 100644 --- a/internal/core/execute/v2/block/msg_common.go +++ b/internal/core/execute/v2/block/msg_common.go @@ -83,13 +83,25 @@ func (m *MessageContext) txnWith(txn *protocol.Transaction) *TransactionContext // isWithin returns true if the given message type appears somewhere in the // message chain. func (m *MessageContext) isWithin(typ ...messaging.MessageType) bool { + newSynth := m.GetActiveGlobals().ExecutorVersion.V2BaikonurEnabled() for { if m.parent == nil { return false } m = m.parent for _, typ := range typ { - if m.message.Type() == typ { + switch { + case typ != messaging.MessageTypeSynthetic && m.message.Type() == typ: + // Check for the given message type + return true + + case !newSynth && m.message.Type() == messaging.MessageTypeBadSynthetic: + // Check for the old synthetic message type + return true + + case newSynth && m.message.Type() == messaging.MessageTypeBadSynthetic, + newSynth && m.message.Type() == messaging.MessageTypeSynthetic: + // Check for either synthetic message type return true } } diff --git a/internal/core/execute/v2/block/msg_synthetic.go b/internal/core/execute/v2/block/msg_synthetic.go index ca5eef7ab..c73532709 100644 --- a/internal/core/execute/v2/block/msg_synthetic.go +++ b/internal/core/execute/v2/block/msg_synthetic.go @@ -18,7 +18,7 @@ import ( ) func init() { - registerSimpleExec[SyntheticMessage](&messageExecutors, messaging.MessageTypeSynthetic) + registerSimpleExec[SyntheticMessage](&messageExecutors, messaging.MessageTypeSynthetic, messaging.MessageTypeBadSynthetic) } // SyntheticMessage records the synthetic transaction but does not execute @@ -37,10 +37,26 @@ func (x SyntheticMessage) Validate(batch *database.Batch, ctx *MessageContext) ( return nil, errors.UnknownError.Wrap(err) } -func (SyntheticMessage) check(batch *database.Batch, ctx *MessageContext) (*messaging.SyntheticMessage, error) { - syn, ok := ctx.message.(*messaging.SyntheticMessage) - if !ok { - return nil, errors.InternalError.WithFormat("invalid message type: expected %v, got %v", messaging.MessageTypeSynthetic, ctx.message.Type()) +func (SyntheticMessage) check(batch *database.Batch, ctx *MessageContext) (*messaging.SynthFields, error) { + // Using messaging.SynthFields is safer than converting one message type + // into the other because that could lead to issues with the different Hash + // method implementations + var syn *messaging.SynthFields + if !ctx.GetActiveGlobals().ExecutorVersion.V2BaikonurEnabled() { + msg, ok := ctx.message.(*messaging.BadSyntheticMessage) + if !ok { + return nil, errors.InternalError.WithFormat("invalid message type: expected %v, got %v", messaging.MessageTypeBadSynthetic, ctx.message.Type()) + } + syn = msg.Data() + } else { + switch msg := ctx.message.(type) { + case *messaging.BadSyntheticMessage: + syn = msg.Data() + case *messaging.SyntheticMessage: + syn = msg.Data() + default: + return nil, errors.InternalError.WithFormat("invalid message type: expected %v, got %v", messaging.MessageTypeSynthetic, ctx.message.Type()) + } } // Basic validation diff --git a/internal/core/execute/v2/block/msg_synthetic_test.go b/internal/core/execute/v2/block/msg_synthetic_test.go index 83ad75b35..8f15d21d7 100644 --- a/internal/core/execute/v2/block/msg_synthetic_test.go +++ b/internal/core/execute/v2/block/msg_synthetic_test.go @@ -49,7 +49,7 @@ func TestSyntheticAnchor(t *testing.T) { Number: 10, } hash := seq.Hash() - syn := &messaging.SyntheticMessage{ + syn := &messaging.BadSyntheticMessage{ Message: seq, Proof: &protocol.AnnotatedReceipt{ Anchor: &protocol.AnchorMetadata{ diff --git a/pkg/types/messaging/enums.yml b/pkg/types/messaging/enums.yml index b604e4789..db69cc402 100644 --- a/pkg/types/messaging/enums.yml +++ b/pkg/types/messaging/enums.yml @@ -5,9 +5,9 @@ MessageType: Signature: value: 2 description: is a signature - Synthetic: + BadSynthetic: value: 3 - description: is a message produced by the protocol, requiring proof + description: is deprecated BlockAnchor: value: 4 description: is a block anchor signed by validator @@ -22,4 +22,7 @@ MessageType: description: is a payment of credits towards a transaction's fee BlockSummary: value: 8 - description: is a summary of a block \ No newline at end of file + description: is a summary of a block + Synthetic: + value: 9 + description: is a message produced by the protocol, requiring proof diff --git a/pkg/types/messaging/enums_gen.go b/pkg/types/messaging/enums_gen.go index 150b47d91..d5be0995d 100644 --- a/pkg/types/messaging/enums_gen.go +++ b/pkg/types/messaging/enums_gen.go @@ -20,8 +20,8 @@ const MessageTypeTransaction MessageType = 1 // MessageTypeSignature is a signature. const MessageTypeSignature MessageType = 2 -// MessageTypeSynthetic is a message produced by the protocol, requiring proof. -const MessageTypeSynthetic MessageType = 3 +// MessageTypeBadSynthetic is deprecated. +const MessageTypeBadSynthetic MessageType = 3 // MessageTypeBlockAnchor is a block anchor signed by validator. const MessageTypeBlockAnchor MessageType = 4 @@ -38,6 +38,9 @@ const MessageTypeCreditPayment MessageType = 7 // MessageTypeBlockSummary is a summary of a block. const MessageTypeBlockSummary MessageType = 8 +// MessageTypeSynthetic is a message produced by the protocol, requiring proof. +const MessageTypeSynthetic MessageType = 9 + // GetEnumValue returns the value of the Message Type func (v MessageType) GetEnumValue() uint64 { return uint64(v) } @@ -45,7 +48,7 @@ func (v MessageType) GetEnumValue() uint64 { return uint64(v) } func (v *MessageType) SetEnumValue(id uint64) bool { u := MessageType(id) switch u { - case MessageTypeTransaction, MessageTypeSignature, MessageTypeSynthetic, MessageTypeBlockAnchor, MessageTypeSequenced, MessageTypeSignatureRequest, MessageTypeCreditPayment, MessageTypeBlockSummary: + case MessageTypeTransaction, MessageTypeSignature, MessageTypeBadSynthetic, MessageTypeBlockAnchor, MessageTypeSequenced, MessageTypeSignatureRequest, MessageTypeCreditPayment, MessageTypeBlockSummary, MessageTypeSynthetic: *v = u return true } @@ -59,8 +62,8 @@ func (v MessageType) String() string { return "transaction" case MessageTypeSignature: return "signature" - case MessageTypeSynthetic: - return "synthetic" + case MessageTypeBadSynthetic: + return "badSynthetic" case MessageTypeBlockAnchor: return "blockAnchor" case MessageTypeSequenced: @@ -71,6 +74,8 @@ func (v MessageType) String() string { return "creditPayment" case MessageTypeBlockSummary: return "blockSummary" + case MessageTypeSynthetic: + return "synthetic" } return fmt.Sprintf("MessageType:%d", v) } @@ -82,8 +87,8 @@ func MessageTypeByName(name string) (MessageType, bool) { return MessageTypeTransaction, true case "signature": return MessageTypeSignature, true - case "synthetic": - return MessageTypeSynthetic, true + case "badsynthetic": + return MessageTypeBadSynthetic, true case "blockanchor": return MessageTypeBlockAnchor, true case "sequenced": @@ -94,6 +99,8 @@ func MessageTypeByName(name string) (MessageType, bool) { return MessageTypeCreditPayment, true case "blocksummary": return MessageTypeBlockSummary, true + case "synthetic": + return MessageTypeSynthetic, true } return 0, false } diff --git a/pkg/types/messaging/messages.yml b/pkg/types/messaging/messages.yml index 8c639d826..a4728e035 100644 --- a/pkg/types/messaging/messages.yml +++ b/pkg/types/messaging/messages.yml @@ -20,6 +20,7 @@ Envelope: repeatable: true TransactionMessage: + # DO NOT ADD ANY OTHER FIELDS TO THIS MESSAGE TYPE union: { type: message } fields: - name: Transaction @@ -28,6 +29,7 @@ TransactionMessage: pointer: true SignatureMessage: + # DO NOT ADD ANY OTHER FIELDS TO THIS MESSAGE TYPE union: { type: message } fields: - name: Signature @@ -58,10 +60,13 @@ SequencedMessage: type: uint optional: true -SyntheticMessage: - # TODO Update to have multiple transactions with a list receipt - union: { type: message } - fields: +# TODO Update synthetic messages to have multiple transactions with a list +# receipt + +SynthFields: + description: contains the fields of a synthetic message + non-binary: true + fields: &synthetic - name: Message type: Message marshal-as: union @@ -73,6 +78,14 @@ SyntheticMessage: marshal-as: reference pointer: true +BadSyntheticMessage: + union: { type: message } + fields: *synthetic + +SyntheticMessage: + union: { type: message } + fields: *synthetic + BlockAnchor: union: { type: message } fields: diff --git a/pkg/types/messaging/synthetic.go b/pkg/types/messaging/synthetic.go new file mode 100644 index 000000000..019ce5046 --- /dev/null +++ b/pkg/types/messaging/synthetic.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Accumulate Authors +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +package messaging + +func (s *BadSyntheticMessage) Data() *SynthFields { + d := new(SynthFields) + d.Message = s.Message + d.Signature = s.Signature + d.Proof = s.Proof + return d +} + +func (s *SyntheticMessage) Data() *SynthFields { + d := new(SynthFields) + d.Message = s.Message + d.Signature = s.Signature + d.Proof = s.Proof + return d +} diff --git a/pkg/types/messaging/types.go b/pkg/types/messaging/types.go index 4712ebcb3..e31ca529e 100644 --- a/pkg/types/messaging/types.go +++ b/pkg/types/messaging/types.go @@ -59,6 +59,10 @@ func (m *SequencedMessage) ID() *url.TxID { return m.Destination.WithTxID(m.Hash()) } +func (m *BadSyntheticMessage) ID() *url.TxID { + return m.Message.ID().Account().WithTxID(m.Hash()) +} + func (m *SyntheticMessage) ID() *url.TxID { return m.Message.ID().Account().WithTxID(m.Hash()) } @@ -91,8 +95,9 @@ func (m *BlockSummary) ID() *url.TxID { return protocol.PartitionUrl(m.Partition).WithTxID(m.Hash()) } -func (m *SyntheticMessage) Unwrap() Message { return m.Message } -func (m *SequencedMessage) Unwrap() Message { return m.Message } +func (m *BadSyntheticMessage) Unwrap() Message { return m.Message } +func (m *SyntheticMessage) Unwrap() Message { return m.Message } +func (m *SequencedMessage) Unwrap() Message { return m.Message } type MessageWithTransaction interface { Message @@ -139,9 +144,10 @@ type MessageWithProduced interface { GetProduced() []*url.TxID } -func (m *SequencedMessage) GetProduced() []*url.TxID { return []*url.TxID{m.Message.ID()} } -func (m *SyntheticMessage) GetProduced() []*url.TxID { return []*url.TxID{m.Message.ID()} } -func (m *SignatureRequest) GetProduced() []*url.TxID { return []*url.TxID{m.TxID} } +func (m *SequencedMessage) GetProduced() []*url.TxID { return []*url.TxID{m.Message.ID()} } +func (m *BadSyntheticMessage) GetProduced() []*url.TxID { return []*url.TxID{m.Message.ID()} } +func (m *SyntheticMessage) GetProduced() []*url.TxID { return []*url.TxID{m.Message.ID()} } +func (m *SignatureRequest) GetProduced() []*url.TxID { return []*url.TxID{m.TxID} } func (m *BlockAnchor) GetProduced() []*url.TxID { id := m.Signature.GetSigner().WithTxID(*(*[32]byte)(m.Signature.Hash())) @@ -149,14 +155,19 @@ func (m *BlockAnchor) GetProduced() []*url.TxID { } func (m *TransactionMessage) Hash() [32]byte { + // A transaction message must contain nothing besides the transaction, so + // this is safe return *(*[32]byte)(m.Transaction.GetHash()) } func (m *SignatureMessage) Hash() [32]byte { + // A signature message must contain nothing besides the signature and + // optionally a transaction hash, so this is safe return *(*[32]byte)(m.Signature.Hash()) } -func (m *SyntheticMessage) Hash() [32]byte { +func (m *BadSyntheticMessage) Hash() [32]byte { + // This is unsafe and buggy, which is why this type is deprecated var h hash.Hasher h.AddHash2(m.Message.Hash()) h.AddHash((*[32]byte)(m.Proof.Receipt.Anchor)) @@ -168,6 +179,7 @@ func (m *BlockAnchor) Hash() [32]byte { return marshalAndHash(m) } func (m *SignatureRequest) Hash() [32]byte { return marshalAndHash(m) } func (m *CreditPayment) Hash() [32]byte { return marshalAndHash(m) } func (m *BlockSummary) Hash() [32]byte { return marshalAndHash(m) } +func (m *SyntheticMessage) Hash() [32]byte { return marshalAndHash(m) } func marshalAndHash(m Message) [32]byte { // If this fails something is seriously wrong diff --git a/pkg/types/messaging/types_gen.go b/pkg/types/messaging/types_gen.go index a2ee4282f..3635c6230 100644 --- a/pkg/types/messaging/types_gen.go +++ b/pkg/types/messaging/types_gen.go @@ -24,6 +24,14 @@ import ( "gitlab.com/accumulatenetwork/accumulate/protocol" ) +type BadSyntheticMessage struct { + fieldsSet []bool + Message Message `json:"message,omitempty" form:"message" query:"message" validate:"required"` + Signature protocol.KeySignature `json:"signature,omitempty" form:"signature" query:"signature" validate:"required"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty" form:"proof" query:"proof" validate:"required"` + extraData []byte +} + type BlockAnchor struct { fieldsSet []bool Signature protocol.KeySignature `json:"signature,omitempty" form:"signature" query:"signature" validate:"required"` @@ -107,6 +115,13 @@ type StateTreeUpdate struct { extraData []byte } +// SynthFields contains the fields of a synthetic message. +type SynthFields struct { + Message Message `json:"message,omitempty" form:"message" query:"message" validate:"required"` + Signature protocol.KeySignature `json:"signature,omitempty" form:"signature" query:"signature" validate:"required"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty" form:"proof" query:"proof" validate:"required"` +} + type SyntheticMessage struct { fieldsSet []bool Message Message `json:"message,omitempty" form:"message" query:"message" validate:"required"` @@ -121,6 +136,8 @@ type TransactionMessage struct { extraData []byte } +func (*BadSyntheticMessage) Type() MessageType { return MessageTypeBadSynthetic } + func (*BlockAnchor) Type() MessageType { return MessageTypeBlockAnchor } func (*BlockSummary) Type() MessageType { return MessageTypeBlockSummary } @@ -137,6 +154,28 @@ func (*SyntheticMessage) Type() MessageType { return MessageTypeSynthetic } func (*TransactionMessage) Type() MessageType { return MessageTypeTransaction } +func (v *BadSyntheticMessage) Copy() *BadSyntheticMessage { + u := new(BadSyntheticMessage) + + if v.Message != nil { + u.Message = CopyMessage(v.Message) + } + if v.Signature != nil { + u.Signature = protocol.CopyKeySignature(v.Signature) + } + if v.Proof != nil { + u.Proof = (v.Proof).Copy() + } + if len(v.extraData) > 0 { + u.extraData = make([]byte, len(v.extraData)) + copy(u.extraData, v.extraData) + } + + return u +} + +func (v *BadSyntheticMessage) CopyAsInterface() interface{} { return v.Copy() } + func (v *BlockAnchor) Copy() *BlockAnchor { u := new(BlockAnchor) @@ -344,6 +383,24 @@ func (v *StateTreeUpdate) Copy() *StateTreeUpdate { func (v *StateTreeUpdate) CopyAsInterface() interface{} { return v.Copy() } +func (v *SynthFields) Copy() *SynthFields { + u := new(SynthFields) + + if v.Message != nil { + u.Message = CopyMessage(v.Message) + } + if v.Signature != nil { + u.Signature = protocol.CopyKeySignature(v.Signature) + } + if v.Proof != nil { + u.Proof = (v.Proof).Copy() + } + + return u +} + +func (v *SynthFields) CopyAsInterface() interface{} { return v.Copy() } + func (v *SyntheticMessage) Copy() *SyntheticMessage { u := new(SyntheticMessage) @@ -382,6 +439,25 @@ func (v *TransactionMessage) Copy() *TransactionMessage { func (v *TransactionMessage) CopyAsInterface() interface{} { return v.Copy() } +func (v *BadSyntheticMessage) Equal(u *BadSyntheticMessage) bool { + if !(EqualMessage(v.Message, u.Message)) { + return false + } + if !(protocol.EqualKeySignature(v.Signature, u.Signature)) { + return false + } + switch { + case v.Proof == u.Proof: + // equal + case v.Proof == nil || u.Proof == nil: + return false + case !((v.Proof).Equal(u.Proof)): + return false + } + + return true +} + func (v *BlockAnchor) Equal(u *BlockAnchor) bool { if !(protocol.EqualKeySignature(v.Signature, u.Signature)) { return false @@ -597,6 +673,25 @@ func (v *StateTreeUpdate) Equal(u *StateTreeUpdate) bool { return true } +func (v *SynthFields) Equal(u *SynthFields) bool { + if !(EqualMessage(v.Message, u.Message)) { + return false + } + if !(protocol.EqualKeySignature(v.Signature, u.Signature)) { + return false + } + switch { + case v.Proof == u.Proof: + // equal + case v.Proof == nil || u.Proof == nil: + return false + case !((v.Proof).Equal(u.Proof)): + return false + } + + return true +} + func (v *SyntheticMessage) Equal(u *SyntheticMessage) bool { if !(EqualMessage(v.Message, u.Message)) { return false @@ -629,6 +724,72 @@ func (v *TransactionMessage) Equal(u *TransactionMessage) bool { return true } +var fieldNames_BadSyntheticMessage = []string{ + 1: "Type", + 2: "Message", + 3: "Signature", + 4: "Proof", +} + +func (v *BadSyntheticMessage) MarshalBinary() ([]byte, error) { + if v == nil { + return []byte{encoding.EmptyObject}, nil + } + + buffer := new(bytes.Buffer) + writer := encoding.NewWriter(buffer) + + writer.WriteEnum(1, v.Type()) + if !(EqualMessage(v.Message, nil)) { + writer.WriteValue(2, v.Message.MarshalBinary) + } + if !(protocol.EqualKeySignature(v.Signature, nil)) { + writer.WriteValue(3, v.Signature.MarshalBinary) + } + if !(v.Proof == nil) { + writer.WriteValue(4, v.Proof.MarshalBinary) + } + + _, _, err := writer.Reset(fieldNames_BadSyntheticMessage) + if err != nil { + return nil, encoding.Error{E: err} + } + buffer.Write(v.extraData) + return buffer.Bytes(), nil +} + +func (v *BadSyntheticMessage) IsValid() error { + var errs []string + + if len(v.fieldsSet) > 0 && !v.fieldsSet[0] { + errs = append(errs, "field Type is missing") + } + if len(v.fieldsSet) > 1 && !v.fieldsSet[1] { + errs = append(errs, "field Message is missing") + } else if EqualMessage(v.Message, nil) { + errs = append(errs, "field Message is not set") + } + if len(v.fieldsSet) > 2 && !v.fieldsSet[2] { + errs = append(errs, "field Signature is missing") + } else if protocol.EqualKeySignature(v.Signature, nil) { + errs = append(errs, "field Signature is not set") + } + if len(v.fieldsSet) > 3 && !v.fieldsSet[3] { + errs = append(errs, "field Proof is missing") + } else if v.Proof == nil { + errs = append(errs, "field Proof is not set") + } + + switch len(errs) { + case 0: + return nil + case 1: + return errors.New(errs[0]) + default: + return errors.New(strings.Join(errs, "; ")) + } +} + var fieldNames_BlockAnchor = []string{ 1: "Type", 2: "Signature", @@ -1329,6 +1490,55 @@ func (v *TransactionMessage) IsValid() error { } } +func (v *BadSyntheticMessage) UnmarshalBinary(data []byte) error { + return v.UnmarshalBinaryFrom(bytes.NewReader(data)) +} + +func (v *BadSyntheticMessage) UnmarshalBinaryFrom(rd io.Reader) error { + reader := encoding.NewReader(rd) + + var vType MessageType + if x := new(MessageType); reader.ReadEnum(1, x) { + vType = *x + } + if !(v.Type() == vType) { + return fmt.Errorf("field Type: not equal: want %v, got %v", v.Type(), vType) + } + + return v.UnmarshalFieldsFrom(reader) +} + +func (v *BadSyntheticMessage) UnmarshalFieldsFrom(reader *encoding.Reader) error { + reader.ReadValue(2, func(r io.Reader) error { + x, err := UnmarshalMessageFrom(r) + if err == nil { + v.Message = x + } + return err + }) + reader.ReadValue(3, func(r io.Reader) error { + x, err := protocol.UnmarshalKeySignatureFrom(r) + if err == nil { + v.Signature = x + } + return err + }) + if x := new(protocol.AnnotatedReceipt); reader.ReadValue(4, x.UnmarshalBinaryFrom) { + v.Proof = x + } + + seen, err := reader.Reset(fieldNames_BadSyntheticMessage) + if err != nil { + return encoding.Error{E: err} + } + v.fieldsSet = seen + v.extraData, err = reader.ReadAll() + if err != nil { + return encoding.Error{E: err} + } + return nil +} + func (v *BlockAnchor) UnmarshalBinary(data []byte) error { return v.UnmarshalBinaryFrom(bytes.NewReader(data)) } @@ -1801,6 +2011,26 @@ func (v *TransactionMessage) UnmarshalFieldsFrom(reader *encoding.Reader) error return nil } +func (v *BadSyntheticMessage) MarshalJSON() ([]byte, error) { + u := struct { + Type MessageType `json:"type"` + Message *encoding.JsonUnmarshalWith[Message] `json:"message,omitempty"` + Signature *encoding.JsonUnmarshalWith[protocol.KeySignature] `json:"signature,omitempty"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty"` + }{} + u.Type = v.Type() + if !(EqualMessage(v.Message, nil)) { + u.Message = &encoding.JsonUnmarshalWith[Message]{Value: v.Message, Func: UnmarshalMessageJSON} + } + if !(protocol.EqualKeySignature(v.Signature, nil)) { + u.Signature = &encoding.JsonUnmarshalWith[protocol.KeySignature]{Value: v.Signature, Func: protocol.UnmarshalKeySignatureJSON} + } + if !(v.Proof == nil) { + u.Proof = v.Proof + } + return json.Marshal(&u) +} + func (v *BlockAnchor) MarshalJSON() ([]byte, error) { u := struct { Type MessageType `json:"type"` @@ -1987,6 +2217,24 @@ func (v *StateTreeUpdate) MarshalJSON() ([]byte, error) { return json.Marshal(&u) } +func (v *SynthFields) MarshalJSON() ([]byte, error) { + u := struct { + Message *encoding.JsonUnmarshalWith[Message] `json:"message,omitempty"` + Signature *encoding.JsonUnmarshalWith[protocol.KeySignature] `json:"signature,omitempty"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty"` + }{} + if !(EqualMessage(v.Message, nil)) { + u.Message = &encoding.JsonUnmarshalWith[Message]{Value: v.Message, Func: UnmarshalMessageJSON} + } + if !(protocol.EqualKeySignature(v.Signature, nil)) { + u.Signature = &encoding.JsonUnmarshalWith[protocol.KeySignature]{Value: v.Signature, Func: protocol.UnmarshalKeySignatureJSON} + } + if !(v.Proof == nil) { + u.Proof = v.Proof + } + return json.Marshal(&u) +} + func (v *SyntheticMessage) MarshalJSON() ([]byte, error) { u := struct { Type MessageType `json:"type"` @@ -2019,6 +2267,35 @@ func (v *TransactionMessage) MarshalJSON() ([]byte, error) { return json.Marshal(&u) } +func (v *BadSyntheticMessage) UnmarshalJSON(data []byte) error { + u := struct { + Type MessageType `json:"type"` + Message *encoding.JsonUnmarshalWith[Message] `json:"message,omitempty"` + Signature *encoding.JsonUnmarshalWith[protocol.KeySignature] `json:"signature,omitempty"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty"` + }{} + u.Type = v.Type() + u.Message = &encoding.JsonUnmarshalWith[Message]{Value: v.Message, Func: UnmarshalMessageJSON} + u.Signature = &encoding.JsonUnmarshalWith[protocol.KeySignature]{Value: v.Signature, Func: protocol.UnmarshalKeySignatureJSON} + u.Proof = v.Proof + if err := json.Unmarshal(data, &u); err != nil { + return err + } + if !(v.Type() == u.Type) { + return fmt.Errorf("field Type: not equal: want %v, got %v", v.Type(), u.Type) + } + if u.Message != nil { + v.Message = u.Message.Value + } + + if u.Signature != nil { + v.Signature = u.Signature.Value + } + + v.Proof = u.Proof + return nil +} + func (v *BlockAnchor) UnmarshalJSON(data []byte) error { u := struct { Type MessageType `json:"type"` @@ -2258,6 +2535,30 @@ func (v *StateTreeUpdate) UnmarshalJSON(data []byte) error { return nil } +func (v *SynthFields) UnmarshalJSON(data []byte) error { + u := struct { + Message *encoding.JsonUnmarshalWith[Message] `json:"message,omitempty"` + Signature *encoding.JsonUnmarshalWith[protocol.KeySignature] `json:"signature,omitempty"` + Proof *protocol.AnnotatedReceipt `json:"proof,omitempty"` + }{} + u.Message = &encoding.JsonUnmarshalWith[Message]{Value: v.Message, Func: UnmarshalMessageJSON} + u.Signature = &encoding.JsonUnmarshalWith[protocol.KeySignature]{Value: v.Signature, Func: protocol.UnmarshalKeySignatureJSON} + u.Proof = v.Proof + if err := json.Unmarshal(data, &u); err != nil { + return err + } + if u.Message != nil { + v.Message = u.Message.Value + } + + if u.Signature != nil { + v.Signature = u.Signature.Value + } + + v.Proof = u.Proof + return nil +} + func (v *SyntheticMessage) UnmarshalJSON(data []byte) error { u := struct { Type MessageType `json:"type"` diff --git a/pkg/types/messaging/unions_gen.go b/pkg/types/messaging/unions_gen.go index c23ab9678..9ac7db39e 100644 --- a/pkg/types/messaging/unions_gen.go +++ b/pkg/types/messaging/unions_gen.go @@ -20,6 +20,8 @@ import ( // NewMessage creates a new Message for the specified MessageType. func NewMessage(typ MessageType) (Message, error) { switch typ { + case MessageTypeBadSynthetic: + return new(BadSyntheticMessage), nil case MessageTypeBlockAnchor: return new(BlockAnchor), nil case MessageTypeBlockSummary: @@ -46,6 +48,12 @@ func EqualMessage(a, b Message) bool { return true } switch a := a.(type) { + case *BadSyntheticMessage: + if a == nil { + return b == nil + } + b, ok := b.(*BadSyntheticMessage) + return ok && a.Equal(b) case *BlockAnchor: if a == nil { return b == nil @@ -101,6 +109,8 @@ func EqualMessage(a, b Message) bool { // CopyMessage copies a Message. func CopyMessage(v Message) Message { switch v := v.(type) { + case *BadSyntheticMessage: + return v.Copy() case *BlockAnchor: return v.Copy() case *BlockSummary: diff --git a/protocol/signature_test.go b/protocol/signature_test.go index f964109ad..743959c60 100644 --- a/protocol/signature_test.go +++ b/protocol/signature_test.go @@ -171,7 +171,7 @@ func TestInitWithOtherKeys(t *testing.T) { // Initialize sim := NewSim(t, simulator.SimpleNetwork(t.Name(), 1, 1), - simulator.GenesisWithVersion(GenesisTime, ExecutorVersionV2Baikonur), + simulator.Genesis(GenesisTime), ) MakeIdentity(t, sim.DatabaseFor(alice), alice) diff --git a/protocol/version.go b/protocol/version.go index 654750747..7db91e79b 100644 --- a/protocol/version.go +++ b/protocol/version.go @@ -11,7 +11,7 @@ type ExecutorVersion uint64 // ExecutorVersionLatest is the latest version of the executor. // ExecutorVersionLatest is intended primarily for testing. -const ExecutorVersionLatest = ExecutorVersionV2 +const ExecutorVersionLatest = ExecutorVersionV2Baikonur // SignatureAnchoringEnabled checks if the version is at least V1 signature anchoring. func (v ExecutorVersion) SignatureAnchoringEnabled() bool { diff --git a/test/simulator/consensus/node.go b/test/simulator/consensus/node.go index 5d47fb0ca..b884c6262 100644 --- a/test/simulator/consensus/node.go +++ b/test/simulator/consensus/node.go @@ -190,6 +190,9 @@ func (n *Node) Check(req *CheckRequest) (*CheckResponse, error) { debug = true case *messaging.BlockAnchor: debug = true + case *messaging.BadSyntheticMessage: + msg = m.Message + goto again case *messaging.SyntheticMessage: msg = m.Message goto again