-
Notifications
You must be signed in to change notification settings - Fork 0
CDCP Core Lib #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MatheusFranco99
wants to merge
84
commits into
main
Choose a base branch
from
cdcp-md-and-impl
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
84 commits
Select commit
Hold shift + click to select a range
dc8d553
Init compose
MatheusFranco99 9219656
fix go mod module declaration
MatheusFranco99 3098e7f
fix go mod renaming
MatheusFranco99 6596525
downgrade go to 1.23.0
MatheusFranco99 b434865
refactor Instance.Chains from field to method
MatheusFranco99 af59b02
Drop unused err and ERChainID field from publisher
MatheusFranco99 b387094
Added features, logging, and comments:
MatheusFranco99 05deb09
Add logging and no limit for proof_window=0 config
MatheusFranco99 1f8c47a
align tests
MatheusFranco99 6bad137
Add proto files and reamde
MatheusFranco99 96f717a
Add publisher interface to scp
MatheusFranco99 4e6df41
Add pending dependency
MatheusFranco99 b67e314
Add periodID to rollback msg
MatheusFranco99 f16afce
Export GenerateInstanceID method
MatheusFranco99 b96001e
Add interface for scp sequencer
MatheusFranco99 7c95866
Add proto with XTRequest with chain id
MatheusFranco99 397ad85
Deprecate Transactions interface for XTRequest explicit structure
MatheusFranco99 4597cc5
Use chain id as uint64
MatheusFranco99 29572a9
rename scp.go to mailbox.go
MatheusFranco99 b384351
Add non-participant check in scp/publisher
MatheusFranco99 6318cbc
Rename proto file
MatheusFranco99 09620b4
participant check refactor
MatheusFranco99 d180d98
Add sbcp-v2 spec file
MatheusFranco99 8fefc57
Add proof pipeline logic to sbcp spec code
MatheusFranco99 90d7ea4
Add deprecated note to sbcp v1
MatheusFranco99 1480ead
Fix lock usage
MatheusFranco99 6ea0acb
check that proof.superblock has finished
MatheusFranco99 5814c6f
align unit tests
MatheusFranco99 2c50d7d
align scp
MatheusFranco99 9c26848
github action for unit tests
MatheusFranco99 c787c13
check for active instances in endblock call in sbcp.sequencer
MatheusFranco99 2c679ab
fix typo
MatheusFranco99 9fc99f6
fix typo
MatheusFranco99 ed1922e
fix plural typo
MatheusFranco99 28b382a
add figures
MatheusFranco99 03dafa1
fix grammar typos and protobuf3 label
MatheusFranco99 2047756
align settlement to new sbcp v2
MatheusFranco99 bfa4f5b
add sequencer number and period ID validation to start instance check
MatheusFranco99 dca0e01
add sbcp readme
MatheusFranco99 f59c1ff
add scp readme
MatheusFranco99 69cad85
refactor util code
MatheusFranco99 82cdcd7
add cdcp markdown
MatheusFranco99 b2fb540
cdcp spec minimal implementation
MatheusFranco99 da998f2
Merge branch 'main' into compose-lib
MatheusFranco99 438759c
fix bold format
MatheusFranco99 2370e40
mention lib in README and fix protocol version
MatheusFranco99 0794e98
fix namings
MatheusFranco99 e1166ec
apply suggestions
MatheusFranco99 2135f96
add pending block check to locked section
MatheusFranco99 7513967
fix memory cleanup
MatheusFranco99 66bab2e
fix instance id computation to encompass chain, tx length, and number…
MatheusFranco99 3b23404
put session id first in case we use it for versioning
MatheusFranco99 015761b
adjust readmes
MatheusFranco99 2a2b6e6
Merge branch 'compose-lib' into cdcp-md-and-impl
MatheusFranco99 3586694
drop unused function
MatheusFranco99 882667e
fix lock
MatheusFranco99 c5f08ad
fix done check
MatheusFranco99 1452b93
unit tests
MatheusFranco99 bd161d8
add error cases
MatheusFranco99 b08aeb5
add comments, checks, and fixed
MatheusFranco99 49647f2
re-order check and add unit tests
MatheusFranco99 4998334
add cdcp readme
MatheusFranco99 0a5d814
clarify hash content
MatheusFranco99 eafc14b
clarify hash content
MatheusFranco99 ef208d8
Merge branch 'compose-lib' into cdcp-md-and-impl
MatheusFranco99 ff18057
rename network proof to superblock proof
MatheusFranco99 18478c6
add target superblock to publisher constructor
MatheusFranco99 4833bb3
remove v1 file
MatheusFranco99 201c4cc
remove v2 mentions
MatheusFranco99 34aa6e0
add golangci lint
MatheusFranco99 5e6b18b
fix linter
MatheusFranco99 c064476
improve readability of StartPeriod
MatheusFranco99 d738783
Revert "improve readability of StartPeriod"
MatheusFranco99 7855cc0
clarify input var names
MatheusFranco99 84de545
Merge branch 'compose-lib' into cdcp-md-and-impl
MatheusFranco99 1f49e15
Merge branch 'main' into cdcp-md-and-impl
MatheusFranco99 89001bd
fix linter issue
MatheusFranco99 84d7483
delete cdcp markdown
MatheusFranco99 8377c9a
fix wrong spaces
MatheusFranco99 495acaa
apply suggestions
MatheusFranco99 8e58dd4
use rwlock
MatheusFranco99 a8fa96b
make external calls unlocked
MatheusFranco99 3ac7a6e
fix comments
MatheusFranco99 f65e0de
O(n*m) to O(n) complexity on checking sent mailbox messages
MatheusFranco99 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
unit tests
- Loading branch information
commit 1452b93ed06da1d85105c73aa5b2a4cb4250ed41
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| package cdcp | ||
|
|
||
| import ( | ||
| "io" | ||
|
|
||
| "github.com/compose-network/specs/compose" | ||
| "github.com/compose-network/specs/compose/scp" | ||
| "github.com/rs/zerolog" | ||
| ) | ||
|
|
||
| func testLogger() zerolog.Logger { | ||
| return zerolog.New(io.Discard) | ||
| } | ||
|
|
||
| type chainRequest struct { | ||
| chain compose.ChainID | ||
| txs [][]byte | ||
| } | ||
|
|
||
| func chainReq(chain compose.ChainID, txs ...[]byte) chainRequest { | ||
| copied := make([][]byte, len(txs)) | ||
| for i, tx := range txs { | ||
| copied[i] = append([]byte(nil), tx...) | ||
| } | ||
| return chainRequest{chain: chain, txs: copied} | ||
| } | ||
|
|
||
| func makeInstance(entries ...chainRequest) compose.Instance { | ||
| return compose.Instance{ | ||
| ID: compose.InstanceID{1}, | ||
| PeriodID: compose.PeriodID(1), | ||
| SequenceNumber: compose.SequenceNumber(1), | ||
| XTRequest: makeXTRequest(entries...), | ||
| } | ||
| } | ||
|
|
||
| func makeXTRequest(entries ...chainRequest) compose.XTRequest { | ||
| req := compose.XTRequest{ | ||
| Transactions: make([]compose.TransactionRequest, len(entries)), | ||
| } | ||
| for i, entry := range entries { | ||
| copied := make([][]byte, len(entry.txs)) | ||
| for j, tx := range entry.txs { | ||
| copied[j] = append([]byte(nil), tx...) | ||
| } | ||
| req.Transactions[i] = compose.TransactionRequest{ | ||
| ChainID: entry.chain, | ||
| Transactions: copied, | ||
| } | ||
| } | ||
| return req | ||
| } | ||
|
|
||
| func cloneInstance(inst compose.Instance) compose.Instance { | ||
| return compose.Instance{ | ||
| ID: inst.ID, | ||
| PeriodID: inst.PeriodID, | ||
| SequenceNumber: inst.SequenceNumber, | ||
| XTRequest: cloneXTRequest(inst.XTRequest), | ||
| } | ||
| } | ||
|
|
||
| func cloneXTRequest(req compose.XTRequest) compose.XTRequest { | ||
| out := compose.XTRequest{ | ||
| Transactions: make([]compose.TransactionRequest, len(req.Transactions)), | ||
| } | ||
| for i, tr := range req.Transactions { | ||
| out.Transactions[i] = compose.TransactionRequest{ | ||
| ChainID: tr.ChainID, | ||
| Transactions: compose.CloneByteSlices(tr.Transactions), | ||
| } | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| type fakePublisherNetwork struct { | ||
| startInstances []compose.Instance | ||
| nativeDecided []struct { | ||
| ID compose.InstanceID | ||
| Result bool | ||
| } | ||
| decisions []struct { | ||
| ID compose.InstanceID | ||
| Result bool | ||
| } | ||
| } | ||
|
|
||
| func (f *fakePublisherNetwork) SendStartInstance(instance compose.Instance) { | ||
| f.startInstances = append(f.startInstances, cloneInstance(instance)) | ||
| } | ||
|
|
||
| func (f *fakePublisherNetwork) SendNativeDecided(instanceID compose.InstanceID, decided bool) { | ||
| f.nativeDecided = append(f.nativeDecided, struct { | ||
| ID compose.InstanceID | ||
| Result bool | ||
| }{ID: instanceID, Result: decided}) | ||
| } | ||
|
|
||
| func (f *fakePublisherNetwork) SendDecided(instanceID compose.InstanceID, decided bool) { | ||
| f.decisions = append(f.decisions, struct { | ||
| ID compose.InstanceID | ||
| Result bool | ||
| }{ID: instanceID, Result: decided}) | ||
| } | ||
|
|
||
| type fakeWSExecutionEngine struct { | ||
| chainID compose.ChainID | ||
| responses []WSSimulationResponse | ||
| requests []WSSimulationRequest | ||
| } | ||
|
|
||
| func (f *fakeWSExecutionEngine) ChainID() compose.ChainID { return f.chainID } | ||
|
|
||
| func (f *fakeWSExecutionEngine) Simulate(req WSSimulationRequest) WSSimulationResponse { | ||
| copied := WSSimulationRequest{ | ||
| SafeExecuteArguments: cloneSafeExecuteArgs(req.SafeExecuteArguments), | ||
| Snapshot: req.Snapshot, | ||
| } | ||
| f.requests = append(f.requests, copied) | ||
|
|
||
| if len(f.responses) == 0 { | ||
| return WSSimulationResponse{} | ||
| } | ||
|
|
||
| resp := f.responses[0] | ||
| f.responses = f.responses[1:] | ||
| return cloneSimulationResponse(resp) | ||
| } | ||
|
|
||
| type fakeWSNetwork struct { | ||
| mailboxMessages []struct { | ||
| to compose.ChainID | ||
| msg scp.MailboxMessage | ||
| } | ||
| decisions []bool | ||
| } | ||
|
|
||
| func (f *fakeWSNetwork) SendMailboxMessage(recipient compose.ChainID, msg scp.MailboxMessage) { | ||
| f.mailboxMessages = append(f.mailboxMessages, struct { | ||
| to compose.ChainID | ||
| msg scp.MailboxMessage | ||
| }{to: recipient, msg: cloneMailboxMessage(msg)}) | ||
| } | ||
|
|
||
| func (f *fakeWSNetwork) SendWSDecidedMessage(decided bool) { | ||
| f.decisions = append(f.decisions, decided) | ||
| } | ||
|
|
||
| type fakeERClient struct { | ||
| err error | ||
| calls []SafeExecuteArguments | ||
| } | ||
|
|
||
| func (f *fakeERClient) SubmitTransaction(args SafeExecuteArguments) error { | ||
| f.calls = append(f.calls, cloneSafeExecuteArgs(args)) | ||
| if f.err != nil { | ||
| return f.err | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func cloneSafeExecuteArgs(args SafeExecuteArguments) SafeExecuteArguments { | ||
| return SafeExecuteArguments{ | ||
| PutInboxMessages: cloneMailboxMessages(args.PutInboxMessages), | ||
| PutOutboxMessages: cloneMailboxMessages(args.PutOutboxMessages), | ||
| Transactions: compose.CloneByteSlices(args.Transactions), | ||
| } | ||
| } | ||
|
|
||
| func cloneSimulationResponse(resp WSSimulationResponse) WSSimulationResponse { | ||
| var read *scp.MailboxMessageHeader | ||
| if resp.ReadMiss != nil { | ||
| copied := *resp.ReadMiss | ||
| read = &copied | ||
| } | ||
| var write *scp.MailboxMessage | ||
| if resp.WriteMiss != nil { | ||
| copied := cloneMailboxMessage(*resp.WriteMiss) | ||
| write = &copied | ||
| } | ||
| return WSSimulationResponse{ | ||
| ReadMiss: read, | ||
| WriteMiss: write, | ||
| WrittenMessages: cloneMailboxMessages(resp.WrittenMessages), | ||
| Err: resp.Err, | ||
| } | ||
| } | ||
|
|
||
| func cloneMailboxMessages(msgs []scp.MailboxMessage) []scp.MailboxMessage { | ||
| out := make([]scp.MailboxMessage, len(msgs)) | ||
| for i, msg := range msgs { | ||
| out[i] = cloneMailboxMessage(msg) | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| func cloneMailboxMessage(msg scp.MailboxMessage) scp.MailboxMessage { | ||
| return scp.MailboxMessage{ | ||
| MailboxMessageHeader: msg.MailboxMessageHeader, | ||
| Data: append([]byte(nil), msg.Data...), | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| package cdcp | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/compose-network/specs/compose" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // TestPublisher_NewInstanceValidatesChains tests that the creation errors if the ER chain has no transaction. | ||
| func TestPublisher_NewInstanceValidatesChains(t *testing.T) { | ||
| instance := makeInstance(chainReq(1, []byte("a"))) | ||
| _, err := NewPublisherInstance(instance, &fakePublisherNetwork{}, compose.ChainID(1), testLogger()) | ||
| require.ErrorIs(t, err, ErrNotEnoughChains) | ||
|
|
||
| instance = makeInstance( | ||
| chainReq(1, []byte("a")), | ||
| chainReq(2, []byte("b")), | ||
| ) | ||
| _, err = NewPublisherInstance(instance, &fakePublisherNetwork{}, compose.ChainID(3), testLogger()) | ||
| require.ErrorIs(t, err, ErrERNotFound) | ||
| } | ||
|
|
||
| func TestPublisher_AllNativeVotesTrueThenWSDecidedTrue(t *testing.T) { | ||
| instance := makeInstance( | ||
| chainReq(1, []byte("a1")), | ||
| chainReq(2, []byte("a2")), | ||
| chainReq(3, []byte("er")), // ER chain | ||
| ) | ||
| net := &fakePublisherNetwork{} | ||
| pub, err := NewPublisherInstance(instance, net, compose.ChainID(3), testLogger()) | ||
| require.NoError(t, err) | ||
|
|
||
| pub.Run() | ||
| // StartInstance message should be sent | ||
| require.Len(t, net.startInstances, 1) | ||
| assert.Equal(t, instance.ID, net.startInstances[0].ID) | ||
|
|
||
| // Processed votes | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(1), true)) | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(2), true)) | ||
| // NativeDecided shoudl be sent with result true | ||
| assert.Len(t, net.nativeDecided, 1) | ||
| assert.True(t, net.nativeDecided[0].Result) | ||
| assert.Equal(t, compose.DecisionStatePending, pub.DecisionState()) | ||
|
|
||
| // Timeout while waiting for WS should be ignored. | ||
| require.NoError(t, pub.Timeout()) | ||
| assert.Len(t, net.decisions, 0) | ||
|
|
||
| // WSDecided should decide the state | ||
| require.NoError(t, pub.ProcessWSDecided(compose.ChainID(3), true)) | ||
| assert.Equal(t, compose.DecisionStateAccepted, pub.DecisionState()) | ||
| require.Len(t, net.decisions, 1) | ||
| assert.True(t, net.decisions[0].Result) | ||
|
|
||
| // Further WS decisions are ignored. | ||
| require.NoError(t, pub.ProcessWSDecided(compose.ChainID(3), true)) | ||
| assert.Len(t, net.decisions, 1) | ||
| } | ||
|
|
||
| func TestPublisher_VoteFalseRejectsImmediately(t *testing.T) { | ||
| instance := makeInstance( | ||
| chainReq(1, []byte("a1")), | ||
| chainReq(2, []byte("a2")), | ||
| chainReq(3, []byte("er")), | ||
| ) | ||
| net := &fakePublisherNetwork{} | ||
| pub, err := NewPublisherInstance(instance, net, compose.ChainID(3), testLogger()) | ||
| require.NoError(t, err) | ||
|
|
||
| pub.Run() | ||
| // A vote of false immediately rejects the instance. | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(1), false)) | ||
| assert.Equal(t, compose.DecisionStateRejected, pub.DecisionState()) | ||
| require.Len(t, net.decisions, 1) | ||
| assert.False(t, net.decisions[0].Result) | ||
| // NativeDecided is sent with result false | ||
| require.Len(t, net.nativeDecided, 1) | ||
| assert.False(t, net.nativeDecided[0].Result) | ||
|
|
||
| // Further votes do not change the outcome. | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(2), true)) | ||
| assert.Len(t, net.decisions, 1) | ||
| assert.Len(t, net.nativeDecided, 1) | ||
| } | ||
|
|
||
| func TestPublisher_VoteErrorsAndTimeout(t *testing.T) { | ||
| instance := makeInstance( | ||
| chainReq(1, []byte("a1")), | ||
| chainReq(2, []byte("a2")), | ||
| chainReq(3, []byte("er")), | ||
| ) | ||
| net := &fakePublisherNetwork{} | ||
| pub, err := NewPublisherInstance(instance, net, compose.ChainID(3), testLogger()) | ||
| require.NoError(t, err) | ||
|
|
||
| pub.Run() | ||
| // Process vote | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(1), true)) | ||
|
|
||
| // Duplicated vote should error | ||
| err = pub.ProcessVote(compose.ChainID(1), true) | ||
| require.ErrorIs(t, err, ErrDuplicatedVote) | ||
|
|
||
| // Vote from non-native chain should error | ||
| err = pub.ProcessVote(compose.ChainID(3), true) | ||
| require.ErrorIs(t, err, ErrVoteSenderNotNativeChain) | ||
|
|
||
| // Timeout while waiting for votes should reject the instance. | ||
| require.NoError(t, pub.Timeout()) | ||
| assert.Equal(t, compose.DecisionStateRejected, pub.DecisionState()) | ||
| require.Len(t, net.decisions, 1) | ||
| assert.False(t, net.decisions[0].Result) | ||
| require.Len(t, net.nativeDecided, 1) | ||
| assert.False(t, net.nativeDecided[0].Result) | ||
|
|
||
| // Timeout after done is ignored. | ||
| require.NoError(t, pub.Timeout()) | ||
| assert.Len(t, net.decisions, 1) | ||
| assert.Len(t, net.nativeDecided, 1) | ||
| } | ||
|
|
||
| func TestPublisher_WSDecidedFalseBeforeVotesComplete(t *testing.T) { | ||
| instance := makeInstance( | ||
| chainReq(1, []byte("a1")), | ||
| chainReq(2, []byte("a2")), | ||
| chainReq(3, []byte("er")), | ||
| ) | ||
| net := &fakePublisherNetwork{} | ||
| pub, err := NewPublisherInstance(instance, net, compose.ChainID(3), testLogger()) | ||
| require.NoError(t, err) | ||
|
|
||
| pub.Run() | ||
| // WSDecided from non-ER chain should error | ||
| err = pub.ProcessWSDecided(compose.ChainID(1), false) | ||
| require.ErrorIs(t, err, ErrNotERChain) | ||
|
|
||
| // WSDecided of false should reject the instance. | ||
| require.NoError(t, pub.ProcessVote(compose.ChainID(1), true)) | ||
| require.NoError(t, pub.ProcessWSDecided(compose.ChainID(3), false)) | ||
| assert.Equal(t, compose.DecisionStateRejected, pub.DecisionState()) | ||
| require.Len(t, net.decisions, 1) | ||
| assert.False(t, net.decisions[0].Result) | ||
| // Native decided should not have been sent because WS terminated early. | ||
| assert.Len(t, net.nativeDecided, 0) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.