Skip to content

Commit

Permalink
Fix synthetic message hash [#3406]
Browse files Browse the repository at this point in the history
Closes #3406. Creates a new synthetic message type with a fixed hash implementation.

Changelog: fix
  • Loading branch information
firelizzard18 committed Sep 23, 2023
1 parent 73c2271 commit 399f1ab
Show file tree
Hide file tree
Showing 17 changed files with 500 additions and 33 deletions.
34 changes: 34 additions & 0 deletions internal/core/execute/multi/multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package execute_test

import (
"fmt"
"math/big"
"testing"

Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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(&timestamp).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(&timestamp).PrivateKey(aliceKey)))

sim.StepUntil(
Txn(st.TxID).Succeeds(),
Txn(st.TxID).Produced().Capture(&st).Succeeds())
}
15 changes: 12 additions & 3 deletions internal/core/execute/v2/block/block_begin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
}
Expand Down
13 changes: 12 additions & 1 deletion internal/core/execute/v2/block/block_end.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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}})
Expand Down
13 changes: 13 additions & 0 deletions internal/core/execute/v2/block/exec_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
14 changes: 13 additions & 1 deletion internal/core/execute/v2/block/msg_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
26 changes: 21 additions & 5 deletions internal/core/execute/v2/block/msg_synthetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion internal/core/execute/v2/block/msg_synthetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
9 changes: 6 additions & 3 deletions pkg/types/messaging/enums.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
description: is a summary of a block
Synthetic:
value: 9
description: is a message produced by the protocol, requiring proof
21 changes: 14 additions & 7 deletions pkg/types/messaging/enums_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -38,14 +38,17 @@ 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) }

// SetEnumValue sets the value. SetEnumValue returns false if the value is invalid.
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
}
Expand All @@ -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:
Expand All @@ -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)
}
Expand All @@ -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":
Expand All @@ -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
}
Expand Down
21 changes: 17 additions & 4 deletions pkg/types/messaging/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Envelope:
repeatable: true

TransactionMessage:
# DO NOT ADD ANY OTHER FIELDS TO THIS MESSAGE TYPE
union: { type: message }
fields:
- name: Transaction
Expand All @@ -28,6 +29,7 @@ TransactionMessage:
pointer: true

SignatureMessage:
# DO NOT ADD ANY OTHER FIELDS TO THIS MESSAGE TYPE
union: { type: message }
fields:
- name: Signature
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
23 changes: 23 additions & 0 deletions pkg/types/messaging/synthetic.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 399f1ab

Please sign in to comment.