This repository was archived by the owner on Aug 2, 2021. It is now read-only.
-
Couldn't load subscription status.
- Fork 110
network: Add adaptive capabilities message #1619
Merged
zelig
merged 42 commits into
ethersphere:master
from
nolash:adaptive-capabilities-msg-nonotify
Aug 16, 2019
Merged
Changes from all commits
Commits
Show all changes
42 commits
Select commit
Hold shift + click to select a range
6529934
network: Add Capability and Capabilities types
nolash 6f76c21
network: Tests pass (but cleanup needed)
nolash 95931c1
network: Remove useless pointers
nolash 532a630
network: Add missing file, extend cap's test, reset altered tests
nolash 01a2e69
network: Add check and test for 'invalid' capabilities
nolash 551169c
network: Move capabilities to BzzAddr
nolash 7af6307
network: Remove redundant Capabilities member on BzzPeer
nolash 511b1a1
network: Add API and test, move adaptive tests to sep file
nolash 5286a73
network: Conceal capability type
nolash b3420aa
network: Change Capabilities to struct, intro change chan
nolash 273397c
network: Add event channel subscribe
nolash bba0cd3
network: Add cleanup on service stop
nolash 776e895
network: Add test for notify in API test
nolash 27ed8b0
network: Add rpc module Subscribe
nolash 1ea689d
network: Reinstate internal channel notify test
nolash 29ed01b
network: Extract API to separate file
nolash 2f1cf1b
network: Remove API files (will be PRd separately)
nolash c26a387
network: Add comments to code
nolash ff9ec84
pss: Remove stray alteration in pss
nolash 6d9259a
network: Speling
nolash 4e674f7
network: Bump protocol version, as rebase updates crossed last one
nolash a7cde4c
network: Delint
nolash d9c79dc
network: Make Capabilities in HandshakeMsg serializable
nolash 1ac7367
network: CapabilitiesMsg add get() instead of fromMsg()
nolash eb5efd0
network: WIP Simplify capabilities objects
nolash 32db8eb
network: WIP Rehabilitate tests after simplification
nolash fb9c2e9
network: WIP revert to rlp encode and export cap/caps fields
nolash 967ba7c
network: Fixed full and light comparisons
nolash 45f8efc
network: WIP custom RLP decoder for Capabilities collection
nolash 86140a5
network: Capabilities RLP Decoder now re-populates id to array idx map
nolash ea8297b
network: Tidy up a bit
nolash 2da509c
network: Add missing tests
nolash 7cd1dd0
network: Rename adaptive.go
nolash 6a5aca6
network: name correction
nolash 1e59e63
network: Remove unused variable
nolash 8fa38a2
network: Replace duplicate ops in rlp decode, simplify names, typos
nolash eaba70f
network: Add comment on cap id index + remove leftover debug
nolash 637178c
network: Remove unused import
nolash 8c8cdbe
network: Remove comment
nolash 5e10954
network: Remove really annoying stdout line
nolash 9c6d4a5
network: Add pointer receivers due to allow mutex reference passing
nolash 69b436a
network: Rename Id->ID, pointer rcv in String()
nolash 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
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,171 @@ | ||
| package network | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sync" | ||
|
|
||
| "github.com/ethereum/go-ethereum/rlp" | ||
| ) | ||
|
|
||
| // CapabilityID defines a unique type of capability | ||
| type CapabilityID uint64 | ||
|
|
||
| // Capability contains a bit vector of flags that define what capability a node has in a specific module | ||
| // The module is defined by the Id. | ||
| type Capability struct { | ||
| Id CapabilityID | ||
| Cap []bool | ||
| } | ||
|
|
||
| // NewCapability initializes a new Capability with the given id and specified number of bits in the vector | ||
| func NewCapability(id CapabilityID, bitCount int) *Capability { | ||
| return &Capability{ | ||
| Id: id, | ||
| Cap: make([]bool, bitCount), | ||
| } | ||
| } | ||
|
|
||
| // Set switches the bit at the specified index on | ||
| func (c *Capability) Set(idx int) error { | ||
| l := len(c.Cap) | ||
| if idx > l-1 { | ||
| return fmt.Errorf("index %d out of bounds (len=%d)", idx, l) | ||
| } | ||
| c.Cap[idx] = true | ||
| return nil | ||
| } | ||
|
|
||
| // Unset switches the bit at the specified index off | ||
| func (c *Capability) Unset(idx int) error { | ||
| l := len(c.Cap) | ||
| if idx > l-1 { | ||
| return fmt.Errorf("index %d out of bounds (len=%d)", idx, l) | ||
| } | ||
| c.Cap[idx] = false | ||
| return nil | ||
| } | ||
|
|
||
| // String implements Stringer interface | ||
| func (c *Capability) String() (s string) { | ||
| s = fmt.Sprintf("%d:", c.Id) | ||
| for _, b := range c.Cap { | ||
| if b { | ||
| s += "1" | ||
| } else { | ||
| s += "0" | ||
| } | ||
| } | ||
| return s | ||
| } | ||
|
|
||
| // IsSameAs returns true if the given Capability object has the identical bit settings as the receiver | ||
| func (c *Capability) IsSameAs(cp *Capability) bool { | ||
| if cp == nil { | ||
| return false | ||
| } | ||
| return isSameBools(c.Cap, cp.Cap) | ||
| } | ||
|
|
||
| func isSameBools(left []bool, right []bool) bool { | ||
| if len(left) != len(right) { | ||
| return false | ||
| } | ||
| for i, b := range left { | ||
| if b != right[i] { | ||
| return false | ||
| } | ||
| } | ||
| return true | ||
| } | ||
|
|
||
| // Capabilities is the collection of capabilities for a Swarm node | ||
| // It is used both to store the capabilities in the node, and | ||
| // to communicate the node capabilities to its peers | ||
| type Capabilities struct { | ||
| idx map[CapabilityID]int // maps the CapabilityIDs to their position in the Caps vector | ||
| Caps []*Capability | ||
| mu sync.Mutex | ||
| } | ||
|
|
||
| // NewCapabilities initializes a new Capabilities object | ||
| func NewCapabilities() *Capabilities { | ||
| return &Capabilities{ | ||
| idx: make(map[CapabilityID]int), | ||
| } | ||
| } | ||
|
|
||
| // adds a capability to the Capabilities collection | ||
| func (c *Capabilities) add(cp *Capability) error { | ||
| if _, ok := c.idx[cp.Id]; ok { | ||
| return fmt.Errorf("Capability id %d already registered", cp.Id) | ||
| } | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| c.Caps = append(c.Caps, cp) | ||
| c.idx[cp.Id] = len(c.Caps) - 1 | ||
| return nil | ||
| } | ||
|
|
||
| // gets the capability with the specified module id | ||
| // returns nil if the id doesn't exist | ||
| func (c *Capabilities) get(id CapabilityID) *Capability { | ||
| idx, ok := c.idx[id] | ||
| if !ok { | ||
| return nil | ||
| } | ||
| return c.Caps[idx] | ||
| } | ||
|
|
||
| // String Implements Stringer interface | ||
| func (c *Capabilities) String() (s string) { | ||
| for _, cp := range c.Caps { | ||
| if s != "" { | ||
| s += "," | ||
| } | ||
| s += cp.String() | ||
| } | ||
| return s | ||
| } | ||
|
|
||
| // DecodeRLP implements rlp.RLPDecoder | ||
| // this custom deserializer builds the module id to array index map | ||
| // state of receiver is undefined on error | ||
| func (c *Capabilities) DecodeRLP(s *rlp.Stream) error { | ||
|
|
||
| // make sure we have a pristine receiver | ||
| c.idx = make(map[CapabilityID]int) | ||
| c.Caps = []*Capability{} | ||
|
|
||
| // discard the Capabilities struct list item | ||
| _, err := s.List() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // discard the Capabilities Caps array list item | ||
| _, err = s.List() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // All elements in array should be Capability type | ||
| for { | ||
| var cap Capability | ||
|
|
||
| // Decode the Capability from the list item | ||
| // if error means the end of the list we're done | ||
| // if not then oh-oh spaghettio's | ||
| err := s.Decode(&cap) | ||
| if err != nil { | ||
| if err == rlp.EOL { | ||
| break | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| // Add the entry to the Capabilities array | ||
| c.add(&cap) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
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,158 @@ | ||
| package network | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "testing" | ||
|
|
||
| "github.com/ethereum/go-ethereum/rlp" | ||
| ) | ||
|
|
||
| // TestCapabilitySetUnset tests that setting and unsetting bits yield expected results | ||
| func TestCapabilitySetUnset(t *testing.T) { | ||
| firstSet := []bool{ | ||
| true, false, false, false, false, false, true, true, false, | ||
| } // 1000 0011 0 | ||
| firstResult := firstSet | ||
| secondSet := []bool{ | ||
| false, true, false, true, false, false, true, false, true, | ||
| } // 0101 0010 1 | ||
| secondResult := []bool{ | ||
| true, true, false, true, false, false, true, true, true, | ||
| } // 1101 0011 1 | ||
| thirdUnset := []bool{ | ||
| true, false, true, true, false, false, true, false, true, | ||
| } // 1011 0010 1 | ||
| thirdResult := []bool{ | ||
| false, true, false, false, false, false, false, true, false, | ||
| } // 0100 0001 0 | ||
|
|
||
| c := NewCapability(42, 9) | ||
| for i, b := range firstSet { | ||
| if b { | ||
| c.Set(i) | ||
| } | ||
| } | ||
| if !isSameBools(c.Cap, firstResult) { | ||
| t.Fatalf("first set result mismatch, expected %v, got %v", firstResult, c.Cap) | ||
| } | ||
|
|
||
| for i, b := range secondSet { | ||
| if b { | ||
| c.Set(i) | ||
| } | ||
| } | ||
| if !isSameBools(c.Cap, secondResult) { | ||
| t.Fatalf("second set result mismatch, expected %v, got %v", secondResult, c.Cap) | ||
| } | ||
|
|
||
| for i, b := range thirdUnset { | ||
| if b { | ||
| c.Unset(i) | ||
| } | ||
| } | ||
| if !isSameBools(c.Cap, thirdResult) { | ||
| t.Fatalf("second set result mismatch, expected %v, got %v", thirdResult, c.Cap) | ||
| } | ||
| } | ||
|
|
||
| // TestCapabilitiesControl tests that the methods for manipulating the capabilities bitvectors set values correctly and return errors when they should | ||
| func TestCapabilitiesControl(t *testing.T) { | ||
|
|
||
| // Initialize capability | ||
| caps := NewCapabilities() | ||
|
|
||
| // Register module. Should succeed | ||
| c1 := NewCapability(1, 16) | ||
| err := caps.add(c1) | ||
| if err != nil { | ||
| t.Fatalf("RegisterCapabilityModule fail: %v", err) | ||
| } | ||
|
|
||
| // Fail if capability id already exists | ||
| c2 := NewCapability(1, 1) | ||
| err = caps.add(c2) | ||
| if err == nil { | ||
| t.Fatalf("Expected RegisterCapabilityModule call with existing id to fail") | ||
| } | ||
|
|
||
| // More than one capabilities flag vector should be possible | ||
| c3 := NewCapability(2, 1) | ||
| err = caps.add(c3) | ||
| if err != nil { | ||
| t.Fatalf("RegisterCapabilityModule (second) fail: %v", err) | ||
| } | ||
| } | ||
|
|
||
| // TestCapabilitiesString checks that the string representation of the capabilities is correct | ||
| func TestCapabilitiesString(t *testing.T) { | ||
| sets1 := []bool{ | ||
| false, false, true, | ||
| } | ||
| c1 := NewCapability(42, len(sets1)) | ||
| for i, b := range sets1 { | ||
| if b { | ||
| c1.Set(i) | ||
| } | ||
| } | ||
| sets2 := []bool{ | ||
| true, false, false, false, true, false, true, false, true, | ||
| } | ||
| c2 := NewCapability(666, len(sets2)) | ||
| for i, b := range sets2 { | ||
| if b { | ||
| c2.Set(i) | ||
| } | ||
| } | ||
|
|
||
| caps := NewCapabilities() | ||
| caps.add(c1) | ||
| caps.add(c2) | ||
|
|
||
| correctString := "42:001,666:100010101" | ||
| if correctString != caps.String() { | ||
| t.Fatalf("Capabilities string mismatch; expected %s, got %s", correctString, caps) | ||
| } | ||
| } | ||
|
|
||
| // TestCapabilitiesRLP ensures that a round of serialization and deserialization of Capabilities object | ||
| // results in the correct data | ||
| func TestCapabilitiesRLP(t *testing.T) { | ||
| c := NewCapabilities() | ||
| cap1 := &Capability{ | ||
| Id: 42, | ||
| Cap: []bool{true, false, true}, | ||
| } | ||
| c.add(cap1) | ||
| cap2 := &Capability{ | ||
| Id: 666, | ||
| Cap: []bool{true, false, true, false, true, true, false, false, true}, | ||
| } | ||
| c.add(cap2) | ||
| buf := bytes.NewBuffer(nil) | ||
| err := rlp.Encode(buf, &c) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| cRestored := NewCapabilities() | ||
| err = rlp.Decode(buf, &cRestored) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
|
|
||
| cap1Restored := cRestored.get(cap1.Id) | ||
| if cap1Restored.Id != cap1.Id { | ||
| t.Fatalf("cap 1 id not correct, expected %d, got %d", cap1.Id, cap1Restored.Id) | ||
| } | ||
| if !cap1.IsSameAs(cap1Restored) { | ||
| t.Fatalf("cap 1 caps not correct, expected %v, got %v", cap1.Cap, cap1Restored.Cap) | ||
| } | ||
|
|
||
| cap2Restored := cRestored.get(cap2.Id) | ||
| if cap2Restored.Id != cap2.Id { | ||
| t.Fatalf("cap 1 id not correct, expected %d, got %d", cap2.Id, cap2Restored.Id) | ||
| } | ||
| if !cap2.IsSameAs(cap2Restored) { | ||
| t.Fatalf("cap 1 caps not correct, expected %v, got %v", cap2.Cap, cap2Restored.Cap) | ||
| } | ||
| } |
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.