-
Notifications
You must be signed in to change notification settings - Fork 956
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
Implement Proposers Submitting Collations onto SMC #111
Implement Proposers Submitting Collations onto SMC #111
Conversation
The architecture of how proposer proposes collation will be based on #122 |
sharding: beginning proposer service tests
sharding/node/node.go
Outdated
@@ -182,6 +183,13 @@ func (n *shardingNode) CreateTXOpts(value *big.Int) (*bind.TransactOpts, error) | |||
}, nil | |||
} | |||
|
|||
// Sign signs the hash of collationHeader contents by | |||
// using default account on keystore and returns signed signature. | |||
func (n *shardingNode) Sign(hash common.Hash) ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not have tests for this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be addressed with #149
sharding/proposer/service_test.go
Outdated
return nil | ||
} | ||
|
||
func (m *mockNode) Close() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yikes, there are ~75 lines of mockNode
and many of these are unused.
Is there a better way to do this?
Can we declare an interface for the proposer expected methods?
Take a look at effective go interface definition: https://golang.org/doc/effective_go.html#interfaces
Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.
What this means to me: we could compose some interface to explain what a proposer-compatible node looks like.
type proposeNode interface {
SMC // SMC interface that has SMCTransactor() and SMCCaller()
Account() (Account, err)
CreateTXOpts() (...)
}
This ~75 lines of setup with some methods that aren't used by this package make me think that we are not properly making use of interfaces. I.e. The consumer (sharding/proposer) should define the interface that it needs to properly function and the producer (sharding/node) simply provides a full struct.
Hopefully, that will reduce boilerplate on the test setup and provide clear isolation of responsibilities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be addressed with #149
sharding/proposer/service_test.go
Outdated
t.Errorf("Create collation failed: %v", err) | ||
} | ||
if collation.Header().Period().Cmp(big.NewInt(5)) != 0 { | ||
t.Errorf("Incorrect collationd period, want 5, got %v ", collation.Header().Period()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
sharding/proposer/service_test.go
Outdated
func TestCheckCollation(t *testing.T) { | ||
backend, smc, err := setup() | ||
if err != nil { | ||
t.Fatalf("Failed to deploy SMC contract: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than repeating this in every test, can you just pass t to setup()
and check this within the setup?
sharding/proposer/service_test.go
Outdated
t.Errorf("Can not check header availability: %v", err) | ||
} | ||
if a { | ||
t.Errorf("Check header avability should return: %v", !a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
sharding/proposer/service_test.go
Outdated
// normal test case 2: check if we can add header for period 2, should return true. | ||
a, err = checkHeaderAvailability(node, big.NewInt(0), big.NewInt(2)) | ||
if !a { | ||
t.Errorf("Check header avability should return: %v", !a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
if collationFromSMC.Proposer != node.Account().Address { | ||
t.Errorf("Incorrect proposer address, got %v", *collation.ProposerAddress()) | ||
} | ||
if common.BytesToHash(collationFromSMC.ChunkRoot[:]) != *collation.Header().ChunkRoot() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need [:]
, what does that do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[:] converts byte[32]
to byte[]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BytesToHash
takes byte[]
mean while ChunkRoot
in SMC is byte[32]
. I need to convert byte[32] to byte[]
sharding/proposer/service_test.go
Outdated
t.Errorf("Can not check header availability: %v", err) | ||
} | ||
if a { | ||
t.Errorf("Check header avability should return: %v", !a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we know that it should return a falsey value. Wouldn't it be better to report the actual value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Good catch!
sharding/proposer/proposer.go
Outdated
} | ||
|
||
var chunkRoot [32]byte | ||
copy(chunkRoot[:], collation.Header().ChunkRoot().Bytes()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to make a copy here? Are you mutating it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not mutating it. I want to convert []byte (what .Bytes() returns) to [32]byte (what SMC takes). Any better idea on how to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work if you do this?
chunkRoot := collation.Header().ChunkRoot().Bytes()[:32]
This should reference the same array in-memory, so you aren't copying the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That doesn't work. I really don't want to copy data. I haven't found a nice way to do it without copying
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What doesn't work about it? This should be a slice referencing the same internal array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still []byte
not [32]byte
. Is this what you are suggesting?
array :=[]byte{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,31}
array32 := array[:32]
fmt.Printf("%T", array32)
I think we can either use the copy function or by assigning array elements one by one but all of these copy data...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After more research, the Go language spec does not allow you to access "directly" the underlying, backing array of a slice. We can do that using package unsafe, but as its name hints: it's unsafe
var (
s []byte // slice
a *[32]byte // pointer to array
)
s = make([]byte, 32)
a = byte32(s)
func byte32(s []byte) (a *[32]byte) {
if len(a) <= len(s) {
a = (*[len(a)]byte)(unsafe.Pointer(&s[0]))
}
return a
}
sharding/proposer/proposer.go
Outdated
var chunkRoot [32]byte | ||
copy(chunkRoot[:], collation.Header().ChunkRoot().Bytes()) | ||
|
||
_, err = n.SMCTransactor().AddHeader(txOps, collation.Header().ShardID(), collation.Header().Period(), chunkRoot) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you throwing away the transaction? Did it succeed? Has it been mined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a check to make sure tx succeeds
sharding/proposer/proposer.go
Outdated
// added to the main chain. There can only be one header per shard | ||
// per period, proposer should check if anyone else has added the header. | ||
// checkHeaderAvailability returns true if it's available, false if it's unavailable. | ||
func checkHeaderAvailability(n node.Node, shardId *big.Int, period *big.Int) (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the name of this method - it seems like it has to do with the whole data availability problem so it's confusing. Let's change to something else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. Changed it to checkHeaderSubmitted
With #149, we now have a simple entry point where we can add all the proposer goroutines. Make sure we leverage as much concurrency as we can for this within the // Start the main loop for proposing collations.
func (p *Proposer) Start() error {
log.Info("Starting proposer service")
// TODO: Propose collations.
return nil
} Let's try to avoid the issue in the notary service as explained in #152. |
I have some issues with the copy requirement conversions from []byte to [32]byte. Is this our code that’s enforcing one or the other? If it’s upstream code, let’s just be sure to comment on the slice operations to fixed size array and vice versa. Specifically, I mean to explain why we do it in a few words. Future readers (like forgetful Preston) will read this code and say “what were they thinking?” and a comment would satisfy this. Thanks |
Below is the code. ChunkRoot is always going to be a hash. The question is how do we convert hash to [32]byte (not []byte) without copying data. I haven't been able to find a good way. Any tips?
|
If its easier to copy, let's just do that for now. My only ask is for a comment to explain why |
Looks good @terenc3t, just open an issue for the TODO |
@prestonvanloon can we get a quick look on this to approve? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, sorry to hold up merging this!
This is a PR referencing #106 to implement a proposer service/protocol that can be used to create collation, sign collation, check SMC header availability and add header to the main chain
Context
To align proposer implementation with minimal sharding protocol. Proposers will be responsible for create collation, sign collation, check collation header availability on the mainchain, add collation header to the mainchain via SMC, and broadcast collation body to the shard network it lives on.
Requirements for Merge
Functions Being Implemented