Frame processing optimisations (#404)

* Make frame processing hashing parallel

* Do not build address for new style proofs

* Validate mint requests in parallel

* Do not recompute byte form of address in mint

* Remove unused output

* Use single append

* Cache verify challenge proof results
This commit is contained in:
petricadaipegsp 2024-12-05 05:57:59 +01:00 committed by GitHub
parent 667b2aa2bc
commit 8a7aae3557
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 310 additions and 84 deletions

View File

@ -76,8 +76,7 @@ var pubSubSet = wire.NewSet(
var engineSet = wire.NewSet(
wire.FieldsOf(new(*config.Config), "Engine"),
crypto.NewWesolowskiFrameProver,
wire.Bind(new(crypto.FrameProver), new(*crypto.WesolowskiFrameProver)),
crypto.NewCachedWesolowskiFrameProver,
crypto.NewKZGInclusionProver,
wire.Bind(new(crypto.InclusionProver), new(*crypto.KZGInclusionProver)),
time.NewMasterTimeReel,

View File

@ -45,14 +45,14 @@ func NewDebugNode(configConfig *config.Config, selfTestReport *protobufs.SelfTes
fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger)
p2PConfig := configConfig.P2P
blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger)
wesolowskiFrameProver := crypto.NewWesolowskiFrameProver(zapLogger)
frameProver := crypto.NewCachedWesolowskiFrameProver(zapLogger)
kzgInclusionProver := crypto.NewKZGInclusionProver(zapLogger)
engineConfig := configConfig.Engine
masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, wesolowskiFrameProver)
masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, frameProver)
inMemoryPeerInfoManager := p2p.NewInMemoryPeerInfoManager(zapLogger)
pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger)
tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport)
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, wesolowskiFrameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport)
tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, frameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport)
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, frameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport)
node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine, pebbleDB)
if err != nil {
return nil, err
@ -71,14 +71,14 @@ func NewNode(configConfig *config.Config, selfTestReport *protobufs.SelfTestRepo
fileKeyManager := keys.NewFileKeyManager(keyConfig, zapLogger)
p2PConfig := configConfig.P2P
blossomSub := p2p.NewBlossomSub(p2PConfig, zapLogger)
wesolowskiFrameProver := crypto.NewWesolowskiFrameProver(zapLogger)
frameProver := crypto.NewCachedWesolowskiFrameProver(zapLogger)
kzgInclusionProver := crypto.NewKZGInclusionProver(zapLogger)
engineConfig := configConfig.Engine
masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, wesolowskiFrameProver)
masterTimeReel := time.NewMasterTimeReel(zapLogger, pebbleClockStore, engineConfig, frameProver)
inMemoryPeerInfoManager := p2p.NewInMemoryPeerInfoManager(zapLogger)
pebbleKeyStore := store.NewPebbleKeyStore(pebbleDB, zapLogger)
tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, wesolowskiFrameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport)
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, wesolowskiFrameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport)
tokenExecutionEngine := token.NewTokenExecutionEngine(zapLogger, configConfig, fileKeyManager, blossomSub, frameProver, kzgInclusionProver, pebbleClockStore, pebbleDataProofStore, pebbleCoinStore, masterTimeReel, inMemoryPeerInfoManager, pebbleKeyStore, selfTestReport)
masterClockConsensusEngine := master.NewMasterClockConsensusEngine(engineConfig, zapLogger, pebbleClockStore, fileKeyManager, blossomSub, kzgInclusionProver, frameProver, masterTimeReel, inMemoryPeerInfoManager, selfTestReport)
node, err := newNode(zapLogger, pebbleDataProofStore, pebbleClockStore, pebbleCoinStore, fileKeyManager, blossomSub, tokenExecutionEngine, masterClockConsensusEngine, pebbleDB)
if err != nil {
return nil, err
@ -136,7 +136,7 @@ var storeSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "DB"), store.NewPe
var pubSubSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "P2P"), p2p.NewInMemoryPeerInfoManager, p2p.NewBlossomSub, wire.Bind(new(p2p.PubSub), new(*p2p.BlossomSub)), wire.Bind(new(p2p.PeerInfoManager), new(*p2p.InMemoryPeerInfoManager)))
var engineSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), crypto.NewWesolowskiFrameProver, wire.Bind(new(crypto.FrameProver), new(*crypto.WesolowskiFrameProver)), crypto.NewKZGInclusionProver, wire.Bind(new(crypto.InclusionProver), new(*crypto.KZGInclusionProver)), time.NewMasterTimeReel, token.NewTokenExecutionEngine)
var engineSet = wire.NewSet(wire.FieldsOf(new(*config.Config), "Engine"), crypto.NewCachedWesolowskiFrameProver, crypto.NewKZGInclusionProver, wire.Bind(new(crypto.InclusionProver), new(*crypto.KZGInclusionProver)), time.NewMasterTimeReel, token.NewTokenExecutionEngine)
var consensusSet = wire.NewSet(master.NewMasterClockConsensusEngine, wire.Bind(
new(consensus.ConsensusEngine),

View File

@ -81,6 +81,7 @@ func (e *DataClockConsensusEngine) prove(
e.clockStore,
e.pubSub,
e.logger,
e.frameProver,
)
if err != nil {
return nil, errors.Wrap(err, "prove")

View File

@ -0,0 +1,111 @@
package crypto
import (
"context"
"encoding/binary"
"io"
"sync"
"time"
"go.uber.org/zap"
"golang.org/x/crypto/sha3"
)
type frameProverCache struct {
FrameProver
ctx context.Context
cancel context.CancelFunc
verifyChallengeProofCache sync.Map
}
var (
_ FrameProver = (*frameProverCache)(nil)
_ io.Closer = (*frameProverCache)(nil)
)
func (c *frameProverCache) gc(ctx context.Context, ttl time.Duration) {
ticker := time.NewTicker(ttl / 2)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
c.verifyChallengeProofCache.Range(func(key, value interface{}) bool {
if entry := value.(*frameProverVerifyChallengeProofCacheEntry); time.Since(entry.createdAt) > ttl {
_ = c.verifyChallengeProofCache.CompareAndDelete(key, value)
}
return true
})
}
}
}
func NewCachedFrameProverWithTTL(prover FrameProver, ttl time.Duration) FrameProver {
ctx, cancel := context.WithCancel(context.Background())
c := &frameProverCache{
FrameProver: prover,
ctx: ctx,
cancel: cancel,
}
go c.gc(ctx, ttl)
return c
}
func NewCachedFrameProver(prover FrameProver) FrameProver {
return NewCachedFrameProverWithTTL(prover, 5*time.Minute)
}
func NewCachedWesolowskiFrameProver(logger *zap.Logger) FrameProver {
return NewCachedFrameProver(NewWesolowskiFrameProver(logger))
}
type frameProverVerifyChallengeProofCacheEntry struct {
done chan struct{}
result bool
createdAt time.Time
}
func (c *frameProverCache) verifyChallengeProofKey(
challenge []byte,
difficulty uint32,
proof [516]byte,
) [552]byte {
h := sha3.Sum256(challenge)
var key [32 + 4 + 516]byte
copy(key[:32], h[:])
binary.BigEndian.PutUint32(key[32:36], difficulty)
copy(key[36:], proof[:])
return key
}
func (c *frameProverCache) VerifyChallengeProof(
challenge []byte,
difficulty uint32,
proof []byte,
) bool {
if len(proof) != 516 {
return false
}
key := c.verifyChallengeProofKey(challenge, difficulty, [516]byte(proof))
entry := &frameProverVerifyChallengeProofCacheEntry{
done: make(chan struct{}),
createdAt: time.Now(),
}
defer close(entry.done)
if entry, loaded := c.verifyChallengeProofCache.LoadOrStore(key, entry); loaded {
entry := entry.(*frameProverVerifyChallengeProofCacheEntry)
<-entry.done
return entry.result
}
entry.result = c.FrameProver.VerifyChallengeProof(challenge, difficulty, proof)
return entry.result
}
func (c *frameProverCache) Close() error {
c.cancel()
return nil
}

View File

@ -0,0 +1,85 @@
package crypto_test
import (
"bytes"
"io"
"testing"
"time"
"github.com/stretchr/testify/assert"
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
)
type mockFrameProver struct {
crypto.FrameProver
verifyChallengeProof func(challenge []byte, difficulty uint32, proof []byte) bool
}
var _ crypto.FrameProver = (*mockFrameProver)(nil)
func (m *mockFrameProver) VerifyChallengeProof(challenge []byte, difficulty uint32, proof []byte) bool {
return m.verifyChallengeProof(challenge, difficulty, proof)
}
func TestCachedFrameProver(t *testing.T) {
t.Parallel()
callCount := 0
prover := &mockFrameProver{
verifyChallengeProof: func(challenge []byte, difficulty uint32, proof []byte) bool {
callCount++
switch {
case bytes.Equal(challenge, []byte{1, 2, 3}):
assert.Equal(t, uint32(42), difficulty)
assert.Equal(t, bytes.Repeat([]byte{0x42}, 516), proof)
return true
case bytes.Equal(challenge, []byte{1, 2, 4}):
assert.Equal(t, uint32(43), difficulty)
assert.Equal(t, bytes.Repeat([]byte{0x43}, 516), proof)
return false
default:
t.Fatal("unexpected call")
return false
}
},
}
cache := crypto.NewCachedFrameProverWithTTL(prover, 500*time.Millisecond)
defer cache.(io.Closer).Close()
// Check that the proof size is checked.
result := cache.VerifyChallengeProof([]byte{1, 2, 3}, 42, []byte{4, 5, 6})
assert.Equal(t, 0, callCount)
assert.False(t, result)
// Check that the result is cached.
result = cache.VerifyChallengeProof([]byte{1, 2, 3}, 42, bytes.Repeat([]byte{0x42}, 516))
assert.Equal(t, 1, callCount)
assert.True(t, result)
result = cache.VerifyChallengeProof([]byte{1, 2, 3}, 42, bytes.Repeat([]byte{0x42}, 516))
assert.Equal(t, 1, callCount)
assert.True(t, result)
// Check that the result is cached in another key.
result = cache.VerifyChallengeProof([]byte{1, 2, 4}, 43, bytes.Repeat([]byte{0x43}, 516))
assert.Equal(t, 2, callCount)
assert.False(t, result)
result = cache.VerifyChallengeProof([]byte{1, 2, 4}, 43, bytes.Repeat([]byte{0x43}, 516))
assert.Equal(t, 2, callCount)
assert.False(t, result)
// Wait for GC.
time.Sleep(time.Second)
// Check that the result is not cached anymore.
result = cache.VerifyChallengeProof([]byte{1, 2, 3}, 42, bytes.Repeat([]byte{0x42}, 516))
assert.Equal(t, 3, callCount)
assert.True(t, result)
// Check that the result is not cached anymore in another key.
result = cache.VerifyChallengeProof([]byte{1, 2, 4}, 43, bytes.Repeat([]byte{0x43}, 516))
assert.Equal(t, 4, callCount)
assert.False(t, result)
}

View File

@ -11,6 +11,7 @@ import (
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"source.quilibrium.com/quilibrium/monorepo/node/config"
qcrypto "source.quilibrium.com/quilibrium/monorepo/node/crypto"
qruntime "source.quilibrium.com/quilibrium/monorepo/node/internal/runtime"
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
@ -37,6 +38,7 @@ type TokenApplication struct {
PubSub p2p.PubSub
Logger *zap.Logger
Difficulty uint32
FrameProver qcrypto.FrameProver
}
func GetOutputsFromClockFrame(
@ -86,6 +88,7 @@ func MaterializeApplicationFromFrame(
clockStore store.ClockStore,
pubSub p2p.PubSub,
logger *zap.Logger,
frameProver qcrypto.FrameProver,
) (*TokenApplication, error) {
_, tokenOutputs, err := GetOutputsFromClockFrame(frame)
if err != nil {
@ -103,6 +106,7 @@ func MaterializeApplicationFromFrame(
Logger: logger,
PubSub: pubSub,
Difficulty: frame.Difficulty,
FrameProver: frameProver,
}, nil
}
@ -144,6 +148,32 @@ func (a *TokenApplication) ApplyTransitions(
requests = transitions.Requests
}
set := make([]*protobufs.TokenRequest, len(requests))
fails := make([]*protobufs.TokenRequest, len(requests))
wg := sync.WaitGroup{}
throttle := make(chan struct{}, qruntime.WorkerCount(0, false))
for i, transition := range requests {
switch t := transition.Request.(type) {
case *protobufs.TokenRequest_Mint:
if t == nil {
fails[i] = transition
continue
}
throttle <- struct{}{}
wg.Add(1)
go func(i int, transition *protobufs.TokenRequest) {
defer func() { <-throttle }()
defer wg.Done()
if err := t.Mint.Validate(); err != nil {
fails[i] = transition
}
}(i, transition)
}
}
wg.Wait()
parallelismMap := map[int]uint64{}
if len(a.Tries) > 1 {
for i := range a.Tries[1:] {
@ -153,38 +183,30 @@ func (a *TokenApplication) ApplyTransitions(
seen := map[string]struct{}{}
set := make([]*protobufs.TokenRequest, len(requests))
fails := make([]*protobufs.TokenRequest, len(set))
outputsSet := make([][]*protobufs.TokenOutput, len(set))
for i, transition := range requests {
i := i
if fails[i] != nil {
continue
}
switch t := transition.Request.(type) {
case *protobufs.TokenRequest_Mint:
if t == nil {
fails[i] = transition
continue
}
if err := t.Mint.Validate(); err != nil {
fails[i] = transition
continue
}
addr, err := poseidon.HashBytes(
t.Mint.Signature.PublicKey.KeyValue,
)
if err != nil {
fails[i] = transition
continue
}
if len(t.Mint.Proofs) == 1 && a.Tries[0].Contains(
addr.FillBytes(make([]byte, 32)),
) && bytes.Equal(t.Mint.Signature.PublicKey.KeyValue, a.Beacon) {
if _, ok := seen[string(t.Mint.Proofs[0][32:])]; !ok {
set[i] = transition
seen[string(t.Mint.Proofs[0][32:])] = struct{}{}
if len(t.Mint.Proofs) == 1 {
addr, err := poseidon.HashBytes(
t.Mint.Signature.PublicKey.KeyValue,
)
if err != nil {
fails[i] = transition
continue
}
if a.Tries[0].Contains(addr.FillBytes(make([]byte, 32))) &&
bytes.Equal(t.Mint.Signature.PublicKey.KeyValue, a.Beacon) {
if _, ok := seen[string(t.Mint.Proofs[0][32:])]; !ok {
set[i] = transition
seen[string(t.Mint.Proofs[0][32:])] = struct{}{}
continue
}
}
fails[i] = transition
continue
} else if len(t.Mint.Proofs) >= 3 && currentFrameNumber > PROOF_FRAME_CUTOFF {
frameNumber := binary.BigEndian.Uint64(t.Mint.Proofs[2])
if frameNumber < currentFrameNumber-2 {
@ -222,6 +244,7 @@ func (a *TokenApplication) ApplyTransitions(
}
}
outputsSet := make([][]*protobufs.TokenOutput, len(set))
successes := make([]*protobufs.TokenRequest, len(set))
for i, transition := range set {
if transition == nil {
@ -363,18 +386,15 @@ func (a *TokenApplication) ApplyTransitions(
}
}
wg := sync.WaitGroup{}
throttle := make(chan struct{}, qruntime.WorkerCount(0, false))
for i, transition := range set {
if transition == nil {
continue
}
i, transition := i, transition
switch t := transition.Request.(type) {
case *protobufs.TokenRequest_Mint:
throttle <- struct{}{}
wg.Add(1)
go func() {
go func(i int, transition *protobufs.TokenRequest) {
defer func() { <-throttle }()
defer wg.Done()
success, err := a.handleMint(
@ -389,7 +409,7 @@ func (a *TokenApplication) ApplyTransitions(
}
outputsSet[i] = success
successes[i] = transition
}()
}(i, transition)
}
}
wg.Wait()

View File

@ -12,7 +12,6 @@ import (
"github.com/pkg/errors"
"go.uber.org/zap"
"golang.org/x/crypto/sha3"
"source.quilibrium.com/quilibrium/monorepo/node/crypto"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
"source.quilibrium.com/quilibrium/monorepo/node/store"
"source.quilibrium.com/quilibrium/monorepo/node/tries"
@ -58,16 +57,17 @@ func (a *TokenApplication) handleMint(
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
addrBytes := addr.FillBytes(make([]byte, 32))
altAddr, err := poseidon.HashBytes([]byte(peerId))
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
altAddrBytes := altAddr.FillBytes(make([]byte, 32))
// todo: set termination frame for this:
if len(t.Proofs) == 1 && a.Tries[0].Contains(
addr.FillBytes(make([]byte, 32)),
) && bytes.Equal(t.Signature.PublicKey.KeyValue, a.Beacon) {
if len(t.Proofs) == 1 && a.Tries[0].Contains(addrBytes) &&
bytes.Equal(t.Signature.PublicKey.KeyValue, a.Beacon) {
if len(t.Proofs[0]) != 64 {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
@ -126,14 +126,12 @@ func (a *TokenApplication) handleMint(
)
ring := -1
for i, t := range a.Tries[1:] {
if t.Contains(altAddr.FillBytes(make([]byte, 32))) {
if t.Contains(altAddrBytes) {
ring = i
}
}
_, prfs, err := a.CoinStore.GetPreCoinProofsForOwner(
altAddr.FillBytes(make([]byte, 32)),
)
_, prfs, err := a.CoinStore.GetPreCoinProofsForOwner(altAddrBytes)
if err != nil {
return nil, errors.Wrap(ErrInvalidStateTransition, "handle mint")
}
@ -167,7 +165,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -195,7 +193,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -255,7 +253,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -293,7 +291,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -302,9 +300,8 @@ func (a *TokenApplication) handleMint(
}}, nil
}
wesoProver := crypto.NewWesolowskiFrameProver(a.Logger)
if bytes.Equal(leaf, bytes.Repeat([]byte{0x00}, 516)) ||
!wesoProver.VerifyChallengeProof(
!a.FrameProver.VerifyChallengeProof(
individualChallenge,
frame.Difficulty,
leaf,
@ -339,6 +336,7 @@ func (a *TokenApplication) handleMint(
}
storage.Quo(storage, big.NewInt(int64(m)))
storage.Mul(storage, big.NewInt(int64(parallelism)))
storageBytes := storage.FillBytes(make([]byte, 32))
a.Logger.Debug(
"issued reward",
@ -356,14 +354,14 @@ func (a *TokenApplication) handleMint(
append([]byte{}, newCommitment...),
newFrameNumber,
),
Amount: storage.FillBytes(make([]byte, 32)),
Amount: storageBytes,
Proof: payload,
Difficulty: a.Difficulty,
Owner: &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -373,13 +371,13 @@ func (a *TokenApplication) handleMint(
&protobufs.TokenOutput{
Output: &protobufs.TokenOutput_Coin{
Coin: &protobufs.Coin{
Amount: storage.FillBytes(make([]byte, 32)),
Amount: storageBytes,
Intersection: make([]byte, 1024),
Owner: &protobufs.AccountRef{
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -403,7 +401,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},
@ -421,7 +419,7 @@ func (a *TokenApplication) handleMint(
Account: &protobufs.AccountRef_ImplicitAccount{
ImplicitAccount: &protobufs.ImplicitAccount{
ImplicitType: 0,
Address: altAddr.FillBytes(make([]byte, 32)),
Address: altAddrBytes,
},
},
},

View File

@ -27,6 +27,7 @@ import (
"source.quilibrium.com/quilibrium/monorepo/node/execution"
"source.quilibrium.com/quilibrium/monorepo/node/execution/intrinsics/token/application"
"source.quilibrium.com/quilibrium/monorepo/node/internal/frametime"
qruntime "source.quilibrium.com/quilibrium/monorepo/node/internal/runtime"
"source.quilibrium.com/quilibrium/monorepo/node/keys"
"source.quilibrium.com/quilibrium/monorepo/node/p2p"
"source.quilibrium.com/quilibrium/monorepo/node/protobufs"
@ -528,6 +529,7 @@ func (e *TokenExecutionEngine) ProcessFrame(
e.clockStore,
e.pubSub,
e.logger,
e.frameProver,
)
if err != nil {
e.logger.Error(
@ -547,10 +549,32 @@ func (e *TokenExecutionEngine) ProcessFrame(
mapSnapshot := ToSerializedMap(e.peerSeniority)
activeMap := NewFromMap(mapSnapshot)
outputAddresses := make([][]byte, len(app.TokenOutputs.Outputs))
outputAddressErrors := make([]error, len(app.TokenOutputs.Outputs))
wg := sync.WaitGroup{}
throttle := make(chan struct{}, qruntime.WorkerCount(0, false))
for i, output := range app.TokenOutputs.Outputs {
throttle <- struct{}{}
wg.Add(1)
go func(i int, output *protobufs.TokenOutput) {
defer func() { <-throttle }()
defer wg.Done()
switch o := output.Output.(type) {
case *protobufs.TokenOutput_Coin:
outputAddresses[i], outputAddressErrors[i] = GetAddressOfCoin(o.Coin, frame.FrameNumber, uint64(i))
case *protobufs.TokenOutput_Proof:
outputAddresses[i], outputAddressErrors[i] = GetAddressOfPreCoinProof(o.Proof)
case *protobufs.TokenOutput_DeletedProof:
outputAddresses[i], outputAddressErrors[i] = GetAddressOfPreCoinProof(o.DeletedProof)
}
}(i, output)
}
wg.Wait()
for i, output := range app.TokenOutputs.Outputs {
switch o := output.Output.(type) {
case *protobufs.TokenOutput_Coin:
address, err := GetAddressOfCoin(o.Coin, frame.FrameNumber, uint64(i))
address, err := outputAddresses[i], outputAddressErrors[i]
if err != nil {
txn.Abort()
return nil, errors.Wrap(err, "process frame")
@ -581,7 +605,7 @@ func (e *TokenExecutionEngine) ProcessFrame(
return nil, errors.Wrap(err, "process frame")
}
case *protobufs.TokenOutput_Proof:
address, err := GetAddressOfPreCoinProof(o.Proof)
address, err := outputAddresses[i], outputAddressErrors[i]
if err != nil {
txn.Abort()
return nil, errors.Wrap(err, "process frame")
@ -619,7 +643,7 @@ func (e *TokenExecutionEngine) ProcessFrame(
}
}
case *protobufs.TokenOutput_DeletedProof:
address, err := GetAddressOfPreCoinProof(o.DeletedProof)
address, err := outputAddresses[i], outputAddressErrors[i]
if err != nil {
txn.Abort()
return nil, errors.Wrap(err, "process frame")
@ -1175,6 +1199,7 @@ func (e *TokenExecutionEngine) VerifyExecution(
e.clockStore,
e.pubSub,
e.logger,
e.frameProver,
)
if err != nil {
return errors.Wrap(err, "verify execution")
@ -1197,6 +1222,7 @@ func (e *TokenExecutionEngine) VerifyExecution(
e.clockStore,
e.pubSub,
e.logger,
e.frameProver,
)
if err != nil {
return errors.Wrap(err, "verify execution")

View File

@ -794,6 +794,7 @@ func processFrame(
clockStore,
nil,
logger,
nil,
)
if err != nil {
logger.Error(

View File

@ -68,9 +68,7 @@ func PackOutputIntoPayloadAndProof(
"pack output into payload and proof",
)
}
for _, sib := range previousTree.Proofs[int(pick)].Siblings {
output = append(output, sib)
}
output = append(output, previousTree.Proofs[int(pick)].Siblings...)
output = append(
output,
binary.BigEndian.AppendUint32(
@ -98,11 +96,6 @@ func UnpackAndVerifyOutput(
modulo = binary.BigEndian.Uint32(output[1])
frameNumber = binary.BigEndian.Uint64(output[2])
payload := []byte("mint")
payload = append(payload, treeRoot...)
payload = binary.BigEndian.AppendUint32(payload, modulo)
payload = binary.BigEndian.AppendUint64(payload, frameNumber)
if len(output) > 3 {
numSiblings := bits.Len64(uint64(modulo) - 1)
if len(output) != 5+numSiblings {
@ -113,16 +106,8 @@ func UnpackAndVerifyOutput(
}
siblings := output[3 : 3+numSiblings]
for _, sib := range siblings {
payload = append(payload, sib...)
}
pathBytes := output[3+numSiblings]
path := binary.BigEndian.Uint32(pathBytes)
payload = binary.BigEndian.AppendUint32(payload, path)
path := binary.BigEndian.Uint32(output[3+numSiblings])
leaf := output[len(output)-1]
payload = append(payload, leaf...)
verified, err = mt.Verify(
NewProofLeaf(leaf),