Skip to content

Commit 89892d8

Browse files
vgonkivsWondertan
andauthored
fraud: fix findings in fraud package (#826)
* fraud: fix all non-functional findings Co-authored-by: Hlib Kanunnikov <[email protected]> Co-authored-by: Hlib Kanunnikov <[email protected]>
1 parent 6a48339 commit 89892d8

File tree

5 files changed

+39
-43
lines changed

5 files changed

+39
-43
lines changed

Diff for: docs/adr/adr-006-fraud-service.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ type BadEncodingProof struct {
7777
}
7878
```
7979

80-
2. Full node broadcasts BEFP to all light nodes via separate sub-service via proto message:
80+
2. Full node broadcasts BEFP to all light and full nodes via separate sub-service via proto message:
8181

8282
```proto3
8383
@@ -125,8 +125,9 @@ type Proof interface {
125125
encoding.BinaryMarshaller
126126
}
127127
```
128+
*Note*: Full node, that detected a malicious block and created a Fraud Proof, will also receive it by subscription to stop respective services.
128129

129-
2a. From the other side, light nodes will, by default, subscribe to the BEFP topic and verify messages received on the topic:
130+
2a. From the other side, nodes will, by default, subscribe to the BEFP topic and verify messages received on the topic:
130131

131132
```go
132133
type ProofUnmarshaller func([]byte) (Proof,error)

Diff for: fraud/bad_encoding.go

+20-19
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ type BadEncodingProof struct {
2525
// Shares that did not pass verification in rmst2d will be nil.
2626
// For non-nil shares MerkleProofs are computed.
2727
Shares []*ipld.ShareWithProof
28-
// Index represents the row/col index where ErrByzantineRow/ErrByzantineColl occurred
29-
Index uint8
30-
// isRow shows that verification failed on row
28+
// Index represents the row/col index where ErrByzantineRow/ErrByzantineColl occurred.
29+
Index uint32
30+
// isRow shows that verification failed on row.
3131
isRow bool
3232
}
3333

34-
// CreateBadEncodingProof creates a new Bad Encoding Fraud Proof that should be propagated through network
34+
// CreateBadEncodingProof creates a new Bad Encoding Fraud Proof that should be propagated through network.
3535
// The fraud proof will contain shares that did not pass verification and their relevant Merkle proofs.
3636
func CreateBadEncodingProof(
3737
hash []byte,
@@ -48,7 +48,7 @@ func CreateBadEncodingProof(
4848
}
4949
}
5050

51-
// Type returns type of fraud proof
51+
// Type returns type of fraud proof.
5252
func (p *BadEncodingProof) Type() ProofType {
5353
return BadEncoding
5454
}
@@ -58,12 +58,12 @@ func (p *BadEncodingProof) HeaderHash() []byte {
5858
return p.headerHash
5959
}
6060

61-
// Height returns block height
61+
// Height returns block height.
6262
func (p *BadEncodingProof) Height() uint64 {
6363
return p.BlockHeight
6464
}
6565

66-
// MarshalBinary converts BadEncodingProof to binary
66+
// MarshalBinary converts BadEncodingProof to binary.
6767
func (p *BadEncodingProof) MarshalBinary() ([]byte, error) {
6868
shares := make([]*ipld_pb.Share, 0, len(p.Shares))
6969
for _, share := range p.Shares {
@@ -74,7 +74,7 @@ func (p *BadEncodingProof) MarshalBinary() ([]byte, error) {
7474
HeaderHash: p.headerHash,
7575
Height: p.BlockHeight,
7676
Shares: shares,
77-
Index: uint32(p.Index),
77+
Index: p.Index,
7878
IsRow: p.isRow,
7979
}
8080
return badEncodingFraudProof.Marshal()
@@ -89,7 +89,7 @@ func UnmarshalBEFP(data []byte) (Proof, error) {
8989
return befp, nil
9090
}
9191

92-
// UnmarshalBinary converts binary to BadEncodingProof
92+
// UnmarshalBinary converts binary to BadEncodingProof.
9393
func (p *BadEncodingProof) UnmarshalBinary(data []byte) error {
9494
in := pb.BadEncoding{}
9595
if err := in.Unmarshal(data); err != nil {
@@ -99,7 +99,7 @@ func (p *BadEncodingProof) UnmarshalBinary(data []byte) error {
9999
headerHash: in.HeaderHash,
100100
BlockHeight: in.Height,
101101
Shares: ipld.ProtoToShare(in.Shares),
102-
Index: uint8(in.Index),
102+
Index: in.Index,
103103
isRow: in.IsRow,
104104
}
105105

@@ -114,23 +114,24 @@ func (p *BadEncodingProof) UnmarshalBinary(data []byte) error {
114114
// and compares it with block's Merkle Root.
115115
func (p *BadEncodingProof) Validate(header *header.ExtendedHeader) error {
116116
if header.Height != int64(p.BlockHeight) {
117-
return errors.New("invalid fraud proof: incorrect block height")
117+
return errors.New("fraud: incorrect block height")
118118
}
119119
merkleRowRoots := header.DAH.RowsRoots
120120
merkleColRoots := header.DAH.ColumnRoots
121121
if len(merkleRowRoots) != len(merkleColRoots) {
122122
// NOTE: This should never happen as callers of this method should not feed it with a
123123
// malformed extended header.
124-
panic(fmt.Sprintf("invalid extended header: length of row and column roots do not match. (rowRoots=%d) (colRoots=%d)",
124+
panic(fmt.Sprintf(
125+
"fraud: invalid extended header: length of row and column roots do not match. (rowRoots=%d) (colRoots=%d)",
125126
len(merkleRowRoots),
126127
len(merkleColRoots)),
127128
)
128129
}
129130
if int(p.Index) >= len(merkleRowRoots) {
130-
return fmt.Errorf("invalid fraud proof: index out of bounds (%d >= %d)", int(p.Index), len(merkleRowRoots))
131+
return fmt.Errorf("fraud: invalid proof: index out of bounds (%d >= %d)", int(p.Index), len(merkleRowRoots))
131132
}
132133
if len(merkleRowRoots) != len(p.Shares) {
133-
return fmt.Errorf("invalid fraud proof: incorrect number of shares %d != %d", len(p.Shares), len(merkleRowRoots))
134+
return fmt.Errorf("fraud: invalid proof: incorrect number of shares %d != %d", len(p.Shares), len(merkleRowRoots))
134135
}
135136

136137
root := merkleRowRoots[p.Index]
@@ -140,19 +141,19 @@ func (p *BadEncodingProof) Validate(header *header.ExtendedHeader) error {
140141

141142
shares := make([][]byte, len(merkleRowRoots))
142143

143-
// verify that Merkle proofs correspond to particular shares
144+
// verify that Merkle proofs correspond to particular shares.
144145
for index, share := range p.Shares {
145146
if share == nil {
146147
continue
147148
}
148149
shares[index] = share.Share
149150
if ok := share.Validate(plugin.MustCidFromNamespacedSha256(root)); !ok {
150-
return fmt.Errorf("invalid fraud proof: incorrect share received at Index %d", index)
151+
return fmt.Errorf("fraud: invalid proof: incorrect share received at index %d", index)
151152
}
152153
}
153154

154155
codec := consts.DefaultCodec()
155-
// rebuild a row or col
156+
// rebuild a row or col.
156157
rebuiltShares, err := codec.Decode(shares)
157158
if err != nil {
158159
return err
@@ -168,9 +169,9 @@ func (p *BadEncodingProof) Validate(header *header.ExtendedHeader) error {
168169
tree.Push(share, rsmt2d.SquareIndex{Axis: uint(p.Index), Cell: uint(i)})
169170
}
170171

171-
// comparing rebuilt Merkle Root of bad row/col with respective Merkle Root of row/col from block
172+
// comparing rebuilt Merkle Root of bad row/col with respective Merkle Root of row/col from block.
172173
if bytes.Equal(tree.Root(), root) {
173-
return errors.New("invalid fraud proof: recomputed Merkle root matches the header's row/column root")
174+
return errors.New("fraud: invalid proof: recomputed Merkle root matches the DAH's row/column root")
174175
}
175176

176177
return nil

Diff for: fraud/bad_encoding_test.go

+9-15
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,26 @@ import (
44
"context"
55
"errors"
66
"testing"
7+
"time"
78

89
mdutils "github.com/ipfs/go-merkledag/test"
910
"github.com/stretchr/testify/require"
10-
"github.com/tendermint/tendermint/pkg/da"
1111

12-
"github.com/celestiaorg/celestia-node/header"
1312
"github.com/celestiaorg/celestia-node/ipld"
1413
)
1514

1615
func TestFraudProofValidation(t *testing.T) {
16+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
17+
defer t.Cleanup(cancel)
1718
bServ := mdutils.Bserv()
18-
eds := ipld.RandEDS(t, 2)
19-
20-
shares := ipld.ExtractEDS(eds)
21-
copy(shares[3][8:], shares[4][8:])
22-
eds, err := ipld.ImportShares(context.Background(), shares, bServ)
19+
_, store := createService(t)
20+
h, err := store.GetByHeight(ctx, 1)
2321
require.NoError(t, err)
24-
da := da.NewDataAvailabilityHeader(eds)
25-
r := ipld.NewRetriever(bServ)
26-
_, err = r.Retrieve(context.Background(), &da)
22+
23+
faultDAH, err := generateByzantineError(ctx, t, h, bServ)
2724
var errByz *ipld.ErrByzantine
2825
require.True(t, errors.As(err, &errByz))
29-
30-
dah := &header.ExtendedHeader{DAH: &da}
31-
32-
p := CreateBadEncodingProof([]byte("hash"), uint64(dah.Height), errByz)
33-
err = p.Validate(dah)
26+
p := CreateBadEncodingProof([]byte("hash"), uint64(faultDAH.Height), errByz)
27+
err = p.Validate(faultDAH)
3428
require.NoError(t, err)
3529
}

Diff for: fraud/proof.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ func (p ProofType) String() string {
1818
case BadEncoding:
1919
return "badencoding"
2020
default:
21-
panic(fmt.Sprintf("invalid proof type: %d", p))
21+
panic(fmt.Sprintf("fraud: invalid proof type: %d", p))
2222
}
2323
}
2424

2525
// Proof is a generic interface that will be used for all types of fraud proofs in the network.
2626
type Proof interface {
27-
// Type returns the exact type of fraud proof
27+
// Type returns the exact type of fraud proof.
2828
Type() ProofType
2929
// HeaderHash returns the block hash.
3030
HeaderHash() []byte
31-
// Height returns the block height corresponding to the Proof
31+
// Height returns the block height corresponding to the Proof.
3232
Height() uint64
3333
// Validate check the validity of fraud proof.
34-
// Validate throws an error if some conditions don't pass and thus fraud proof is not valid
35-
// NOTE: header.ExtendedHeader should pass basic validation otherwise it will panic if it's malformed
34+
// Validate throws an error if some conditions don't pass and thus fraud proof is not valid.
35+
// NOTE: header.ExtendedHeader should pass basic validation otherwise it will panic if it's malformed.
3636
Validate(*header.ExtendedHeader) error
3737

3838
encoding.BinaryMarshaler

Diff for: ipld/retriever_byzantine.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
// It is converted from rsmt2d.ByzantineRow/Col +
1818
// Merkle Proof for each share.
1919
type ErrByzantine struct {
20-
Index uint8
20+
Index uint32
2121
Shares []*ShareWithProof
2222
// TODO(@vgokivs): Change to enum type and rename to Axis after
2323
// updating rsmt2d
@@ -57,7 +57,7 @@ func NewErrByzantine(
5757
}
5858

5959
return &ErrByzantine{
60-
Index: uint8(errByz.Index),
60+
Index: uint32(errByz.Index),
6161
Shares: sharesWithProof,
6262
IsRow: errByz.Axis == rsmt2d.Row,
6363
}

0 commit comments

Comments
 (0)