Skip to content

Commit

Permalink
feat: dispersed replica validation (#4522)
Browse files Browse the repository at this point in the history
  • Loading branch information
nugaon authored Dec 19, 2023
1 parent 590e96a commit 2331ef0
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 16 deletions.
15 changes: 2 additions & 13 deletions pkg/file/redundancy/getter/getter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func testDecodingRACE(t *testing.T, bufSize, shardCnt, erasureCnt int) {
err := context.DeadlineExceeded
select {
case err = <-q:
case <-time.After(getter.StrategyTimeout * 4):
case <-time.After(getter.StrategyTimeout * 10):
}
switch {
case erasureCnt > parityCnt:
Expand Down Expand Up @@ -228,17 +228,6 @@ func testDecodingFallback(t *testing.T, s getter.Strategy, strict bool) {
waitErased <- err
}()

// set timeouts for the cases
var timeout time.Duration
switch {
case strict:
timeout = 2*getter.StrategyTimeout - 10*time.Millisecond
case s == getter.NONE:
timeout = 4*getter.StrategyTimeout - 10*time.Millisecond
case s == getter.DATA:
timeout = 3*getter.StrategyTimeout - 10*time.Millisecond
}

// wait for delayed chunk retrieval to complete
select {
case err := <-waitDelayed:
Expand Down Expand Up @@ -297,7 +286,7 @@ func testDecodingFallback(t *testing.T, s getter.Strategy, strict bool) {
t.Fatal("unexpected timeout using strategy", s, "with strict", strict)
}
}
case <-time.After(timeout):
case <-time.After(getter.StrategyTimeout * 3):
if !strict || s != getter.NONE {
t.Fatal("unexpected timeout using strategy", s, "with strict", strict)
}
Expand Down
4 changes: 1 addition & 3 deletions pkg/replicas/replicas.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ package replicas

import (
"context"
"encoding/hex"
"time"

"github.com/ethersphere/bee/pkg/crypto"
Expand All @@ -29,7 +28,6 @@ var (
RetryInterval = 300 * time.Millisecond
privKey, _ = crypto.DecodeSecp256k1PrivateKey(append([]byte{1}, make([]byte, 31)...))
signer = crypto.NewDefaultSigner(privKey)
owner, _ = hex.DecodeString("dc5b20847f43d67928f49cd4f85d696b5a7617b5")
)

// SetLevel sets the redundancy level in the context
Expand Down Expand Up @@ -82,7 +80,7 @@ func (rr *replicator) replicate(i uint8) (sp *replica) {
// calculate SOC address for potential replica
h := swarm.NewHasher()
_, _ = h.Write(id)
_, _ = h.Write(owner)
_, _ = h.Write(swarm.ReplicasOwner)
return &replica{h.Sum(nil), id}
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/soc/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
package soc

import (
"bytes"

"github.com/ethersphere/bee/pkg/swarm"
)

Expand All @@ -15,6 +17,11 @@ func Valid(ch swarm.Chunk) bool {
return false
}

// disperse replica validation
if bytes.Equal(s.owner, swarm.ReplicasOwner) && !bytes.Equal(s.WrappedChunk().Address().Bytes()[1:32], s.id[1:32]) {
return false
}

address, err := s.Address()
if err != nil {
return false
Expand Down
58 changes: 58 additions & 0 deletions pkg/soc/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
package soc_test

import (
"crypto/rand"
"io"
"strings"
"testing"

"github.com/ethersphere/bee/pkg/cac"
"github.com/ethersphere/bee/pkg/crypto"
"github.com/ethersphere/bee/pkg/soc"
"github.com/ethersphere/bee/pkg/swarm"
)
Expand All @@ -31,6 +35,60 @@ func TestValid(t *testing.T) {
}
}

// TestValidDispersedReplica verifies that the validator can detect
// valid dispersed replicas chunks.
func TestValidDispersedReplica(t *testing.T) {
t.Parallel()

t.Run("valid", func(t *testing.T) {
privKey, _ := crypto.DecodeSecp256k1PrivateKey(append([]byte{1}, make([]byte, 31)...))
signer := crypto.NewDefaultSigner(privKey)

chData := make([]byte, swarm.ChunkSize)
_, _ = io.ReadFull(rand.Reader, chData)
ch, err := cac.New(chData)
if err != nil {
t.Fatal(err)
}
id := append([]byte{1}, ch.Address().Bytes()[1:]...)

socCh, err := soc.New(id, ch).Sign(signer)
if err != nil {
t.Fatal(err)
}

// check valid chunk
if !soc.Valid(socCh) {
t.Fatal("dispersed replica chunk is invalid")
}
})

t.Run("invalid", func(t *testing.T) {
privKey, _ := crypto.DecodeSecp256k1PrivateKey(append([]byte{1}, make([]byte, 31)...))
signer := crypto.NewDefaultSigner(privKey)

chData := make([]byte, swarm.ChunkSize)
_, _ = io.ReadFull(rand.Reader, chData)
ch, err := cac.New(chData)
if err != nil {
t.Fatal(err)
}
id := append([]byte{1}, ch.Address().Bytes()[1:]...)
// change to invalid ID
id[2] += 1

socCh, err := soc.New(id, ch).Sign(signer)
if err != nil {
t.Fatal(err)
}

// check valid chunk
if soc.Valid(socCh) {
t.Fatal("dispersed replica should be invalid")
}
})
}

// TestInvalid verifies that the validator can detect chunks
// with invalid data and invalid address.
func TestInvalid(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/swarm/swarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ var (
ErrInvalidChunk = errors.New("invalid chunk")
)

var (
// Ethereum Address for SOC owner of Dispersed Replicas
// generated from private key 0x0100000000000000000000000000000000000000000000000000000000000000
ReplicasOwner, _ = hex.DecodeString("dc5b20847f43d67928f49cd4f85d696b5a7617b5")
)

var (
// EmptyAddress is the address that is all zeroes.
EmptyAddress = NewAddress(make([]byte, HashSize))
Expand Down

0 comments on commit 2331ef0

Please sign in to comment.