From 8a7aae3557dc6f8199520fa598a30e79f9979507 Mon Sep 17 00:00:00 2001 From: petricadaipegsp <155911522+petricadaipegsp@users.noreply.github.com> Date: Thu, 5 Dec 2024 05:57:59 +0100 Subject: [PATCH] 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 --- node/app/wire.go | 3 +- node/app/wire_gen.go | 18 +-- node/consensus/data/consensus_frames.go | 1 + node/crypto/frame_prover_cache.go | 111 ++++++++++++++++++ node/crypto/frame_prover_cache_test.go | 85 ++++++++++++++ .../token/application/token_application.go | 86 ++++++++------ .../token/application/token_handle_mint.go | 38 +++--- .../token/token_execution_engine.go | 32 ++++- node/main.go | 1 + node/tries/proof_leaf.go | 19 +-- 10 files changed, 310 insertions(+), 84 deletions(-) create mode 100644 node/crypto/frame_prover_cache.go create mode 100644 node/crypto/frame_prover_cache_test.go diff --git a/node/app/wire.go b/node/app/wire.go index f5b84e5..990cf86 100644 --- a/node/app/wire.go +++ b/node/app/wire.go @@ -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, diff --git a/node/app/wire_gen.go b/node/app/wire_gen.go index 961193c..a8da265 100644 --- a/node/app/wire_gen.go +++ b/node/app/wire_gen.go @@ -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), diff --git a/node/consensus/data/consensus_frames.go b/node/consensus/data/consensus_frames.go index 3561a77..bd7c5fd 100644 --- a/node/consensus/data/consensus_frames.go +++ b/node/consensus/data/consensus_frames.go @@ -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") diff --git a/node/crypto/frame_prover_cache.go b/node/crypto/frame_prover_cache.go new file mode 100644 index 0000000..288208d --- /dev/null +++ b/node/crypto/frame_prover_cache.go @@ -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 +} diff --git a/node/crypto/frame_prover_cache_test.go b/node/crypto/frame_prover_cache_test.go new file mode 100644 index 0000000..48f0c95 --- /dev/null +++ b/node/crypto/frame_prover_cache_test.go @@ -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) +} diff --git a/node/execution/intrinsics/token/application/token_application.go b/node/execution/intrinsics/token/application/token_application.go index d7c57ca..9126d47 100644 --- a/node/execution/intrinsics/token/application/token_application.go +++ b/node/execution/intrinsics/token/application/token_application.go @@ -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() diff --git a/node/execution/intrinsics/token/application/token_handle_mint.go b/node/execution/intrinsics/token/application/token_handle_mint.go index 870396b..dfb23ee 100644 --- a/node/execution/intrinsics/token/application/token_handle_mint.go +++ b/node/execution/intrinsics/token/application/token_handle_mint.go @@ -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, }, }, }, diff --git a/node/execution/intrinsics/token/token_execution_engine.go b/node/execution/intrinsics/token/token_execution_engine.go index 49d0ebb..a59a553 100644 --- a/node/execution/intrinsics/token/token_execution_engine.go +++ b/node/execution/intrinsics/token/token_execution_engine.go @@ -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") diff --git a/node/main.go b/node/main.go index a94e2a5..35154ce 100644 --- a/node/main.go +++ b/node/main.go @@ -794,6 +794,7 @@ func processFrame( clockStore, nil, logger, + nil, ) if err != nil { logger.Error( diff --git a/node/tries/proof_leaf.go b/node/tries/proof_leaf.go index 087a6d8..52148f4 100644 --- a/node/tries/proof_leaf.go +++ b/node/tries/proof_leaf.go @@ -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),