Skip to content

Commit

Permalink
Merge branch 'main' of gitlab.com:accumulatenetwork/accumulate
Browse files Browse the repository at this point in the history
  • Loading branch information
firelizzard18 committed Oct 2, 2023
2 parents 1ee26e7 + 8c41226 commit 3b63d2c
Show file tree
Hide file tree
Showing 27 changed files with 809 additions and 184 deletions.
2 changes: 2 additions & 0 deletions internal/core/execute/v2/block/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type Block struct {
State BlockState
Batch *database.Batch
Executor *Executor

syntheticCount uint64
}

func (b *Block) Params() execute.BlockParams { return b.BlockParams }
Expand Down
69 changes: 54 additions & 15 deletions internal/core/execute/v2/block/exec_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
"gitlab.com/accumulatenetwork/accumulate/internal/database"
"gitlab.com/accumulatenetwork/accumulate/pkg/errors"
"gitlab.com/accumulatenetwork/accumulate/pkg/types/messaging"
"gitlab.com/accumulatenetwork/accumulate/pkg/url"
"gitlab.com/accumulatenetwork/accumulate/protocol"
"golang.org/x/exp/slog"
)

// bundle is a bundle of messages to be processed.
Expand Down Expand Up @@ -46,7 +48,7 @@ func (b *Block) Process(envelope *messaging.Envelope) ([]*protocol.TransactionSt
}

// Make sure every transaction is signed
err = checkForUnsignedTransactions(messages)
err = b.Executor.checkForUnsignedTransactions(messages)
if err != nil {
return nil, errors.UnknownError.Wrap(err)
}
Expand Down Expand Up @@ -194,6 +196,20 @@ func (d *bundle) process() ([]*protocol.TransactionStatus, error) {
d.produced = append(d.produced, ctx.produced...)
}

// Check for duplicates. This is a serious error if it occurs, but returning
// an error here would effectively stall the network.
pCount := map[[32]byte]int{}
pID := map[[32]byte]*url.TxID{}
for _, m := range d.produced {
pCount[m.Message.Hash()]++
pID[m.Message.Hash()] = m.Message.ID()
}
for h, c := range pCount {
if c > 1 {
slog.ErrorCtx(d.Context, "Duplicate synthetic messages", "id", pID[h], "count", c)
}
}

// Execute produced messages immediately if and only if the producer and
// destination are in the same domain. This implementation is inefficient
// but it preserves order and its good enough for now.
Expand Down Expand Up @@ -229,26 +245,49 @@ func (d *bundle) process() ([]*protocol.TransactionStatus, error) {

// checkForUnsignedTransactions returns an error if the message bundle includes
// any unsigned transactions.
func checkForUnsignedTransactions(messages []messaging.Message) error {
unsigned := set[[32]byte]{}
func (x *Executor) checkForUnsignedTransactions(messages []messaging.Message) error {
// Record signatures and transactions
haveSigFor := map[[32]byte]bool{}
haveTxn := map[[32]byte]bool{}
for _, msg := range messages {
if msg, ok := msg.(*messaging.TransactionMessage); ok {
unsigned[msg.ID().Hash()] = struct{}{}
if x.globals.Active.ExecutorVersion.V2BaikonurEnabled() {
if _, ok := msg.(*messaging.BlockAnchor); ok {
continue
}
}

if msg, ok := messaging.UnwrapAs[messaging.MessageForTransaction](msg); ok {
// User signatures can be sent without a transaction, but authority
// signatures and other message-for-transaction types cannot
sig, ok := msg.(*messaging.SignatureMessage)
isUser := ok && sig.Signature.Type() != protocol.SignatureTypeAuthority
haveSigFor[msg.GetTxID().Hash()] = isUser
}

if txn, ok := msg.(*messaging.TransactionMessage); ok {
isRemote := txn.GetTransaction().Body.Type() == protocol.TransactionTypeRemote
haveTxn[txn.ID().Hash()] = isRemote
}
}
for _, msg := range messages {
again:
switch m := msg.(type) {
case messaging.MessageForTransaction:
delete(unsigned, m.GetTxID().Hash())
case interface{ Unwrap() messaging.Message }:
msg = m.Unwrap()
goto again

// If a transaction does not have a signature, reject the bundle
for txn := range haveTxn {
if _, has := haveSigFor[txn]; !has {
return errors.BadRequest.With("message bundle includes an unsigned transaction")
}
}
if len(unsigned) > 0 {
return errors.BadRequest.With("message bundle includes an unsigned transaction")

// If an authority signature or other synthetic message-for-transaction is
// sent without its transaction, reject the bundle
if x.globals.Active.ExecutorVersion.V2BaikonurEnabled() {
for txn, isUserSig := range haveSigFor {
isRemote, has := haveTxn[txn]
if !isUserSig && (!has || isRemote) {
return errors.BadRequest.With("message bundle is missing a transaction")
}
}
}

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/core/execute/v2/block/exec_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (x *Executor) Validate(envelope *messaging.Envelope, _ bool) ([]*protocol.T
}

// Make sure every transaction is signed
err = checkForUnsignedTransactions(messages)
err = x.checkForUnsignedTransactions(messages)
if err != nil {
return nil, errors.UnknownError.Wrap(err)
}
Expand Down
34 changes: 29 additions & 5 deletions internal/core/execute/v2/block/msg_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"gitlab.com/accumulatenetwork/accumulate/pkg/types/messaging"
"gitlab.com/accumulatenetwork/accumulate/pkg/url"
"gitlab.com/accumulatenetwork/accumulate/protocol"
"golang.org/x/exp/slog"
)

// MessageContext is the context in which a message is processed.
Expand Down Expand Up @@ -151,14 +152,37 @@ func (m *MessageContext) queueAdditional(msg messaging.Message) {

// didProduce queues a produced synthetic message for dispatch.
func (m *MessageContext) didProduce(batch *database.Batch, dest *url.URL, msg messaging.Message) error {
if dest == nil {
panic("nil destination for produced message")
}
m.produced = append(m.produced, &ProducedMessage{
p := &ProducedMessage{
Producer: m.message.ID(),
Destination: dest,
Message: msg,
})
}

// Add an index to synthetic transactions to differentiate otherwise
// identical messages
m.syntheticCount++
switch msg := msg.(type) {
case *messaging.TransactionMessage:
if !m.GetActiveGlobals().ExecutorVersion.V2BaikonurEnabled() {
break
}

// SyntheticForwardTransaction is the only synthetic transaction type
// that does not satisfy this interface, but they are not used in v2
txn, ok := msg.Transaction.Body.(protocol.SyntheticTransaction)
if !ok {
slog.ErrorCtx(m.Context, "Synthetic transaction is not synthetic", "id", msg.ID())
break
}

txn.SetIndex(m.syntheticCount)
p.Message = msg.Copy() // Clear memoized hashes
}

if dest == nil {
panic("nil destination for produced message")
}
m.produced = append(m.produced, p)

err := batch.Message(m.message.Hash()).Produced().Add(msg.ID())
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/core/execute/v2/block/msg_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,9 +394,9 @@ func (x TransactionMessage) executeTransaction(batch *database.Batch, ctx *Trans

func (x TransactionMessage) postProcess(batch *database.Batch, ctx *TransactionContext, state *chain.ProcessTransactionState, delivered bool) error {
// Calculate refunds
var swos []protocol.SynthTxnWithOrigin
var swos []protocol.SyntheticTransaction
for _, newTxn := range state.ProducedTxns {
if swo, ok := newTxn.Body.(protocol.SynthTxnWithOrigin); ok {
if swo, ok := newTxn.Body.(protocol.SyntheticTransaction); ok {
swos = append(swos, swo)
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/core/execute/v2/block/synthetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (x *Executor) produceSynthetic(batch *database.Batch, produced []*ProducedM
// transaction. setSyntheticOrigin sets the refund amount for each synthetic
// transaction, spreading the potential refund across all produced synthetic
// transactions.
func (x *Executor) setSyntheticOrigin(batch *database.Batch, from *protocol.Transaction, produced []protocol.SynthTxnWithOrigin) error {
func (x *Executor) setSyntheticOrigin(batch *database.Batch, from *protocol.Transaction, produced []protocol.SyntheticTransaction) error {
for _, swo := range produced {
swo.SetCause(from.ID().Hash(), from.ID().Account())
}
Expand Down
2 changes: 1 addition & 1 deletion internal/core/execute/v2/block/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ func (x *TransactionContext) recordFailedTransaction(batch *database.Batch, deli
}

// If this transaction is a synthetic transaction, send a refund
if swo, ok := delivery.Transaction.Body.(protocol.SynthTxnWithOrigin); ok {
if swo, ok := delivery.Transaction.Body.(protocol.SyntheticTransaction); ok {
init, refundAmount := swo.GetRefund()
if refundAmount > 0 {
refund := new(protocol.SyntheticDepositCredits)
Expand Down
15 changes: 0 additions & 15 deletions internal/core/execute/v2/block/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,6 @@ import (
"gitlab.com/accumulatenetwork/accumulate/protocol"
)

// none is an empty struct.
type none = struct{}

// set is an unordered set of T implemented as a map of T to [none].
type set[T comparable] map[T]none

// Add adds a value to the set.
func (s set[T]) Add(v T) { s[v] = none{} }

// Remove removes a value from the set.
func (s set[T]) Remove(v T) { delete(s, v) }

// Hash checks if the set has the given value.
func (s set[T]) Has(v T) bool { _, ok := s[v]; return ok }

// orderedMap is an ordered map from K to V implemented with a builtin map,
// slice of keys, and comparison function.
type orderedMap[K comparable, V any] struct {
Expand Down
35 changes: 0 additions & 35 deletions pkg/errors/deprecated.go

This file was deleted.

8 changes: 5 additions & 3 deletions pkg/errors/error.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Error:
ErrorBase[Status statusType]:
fields:
- name: Message
type: string
Expand All @@ -7,14 +7,16 @@ Error:
marshal-as: enum
- { name: CodeID, type: uint, virtual: true, non-binary: true }
- name: Cause
type: Error
type: { name: ErrorBase, parameters: [{ type: Status }] }
marshal-as: reference
pointer: true
- name: CallStack
type: CallSite
marshal-as: reference
pointer: true
repeatable: true
- name: Data
type: rawJson

CallSite:
fields:
Expand All @@ -23,4 +25,4 @@ CallSite:
- name: File
type: string
- name: Line
type: int
type: int
Loading

0 comments on commit 3b63d2c

Please sign in to comment.