bindings_test.go 4.55 KB
Newer Older
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package go_sectorbuilder_test

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"testing"
	"time"
	"unsafe"

	sb "github.com/filecoin-project/go-sectorbuilder"

	"github.com/stretchr/testify/require"
)

func TestSectorBuilderLifecycle(t *testing.T) {
	metadataDir := requireTempDirPath(t)
	defer require.NoError(t, os.Remove(metadataDir))

	sealedSectorDir := requireTempDirPath(t)
	defer require.NoError(t, os.Remove(sealedSectorDir))

	stagedSectorDir := requireTempDirPath(t)
	defer require.NoError(t, os.Remove(stagedSectorDir))

	ptr, err := sb.InitSectorBuilder(1024, 2, 1, 0, metadataDir, [31]byte{}, sealedSectorDir, stagedSectorDir, 1)
	require.NoError(t, err)
	defer sb.DestroySectorBuilder(ptr)

	// compute the max user-bytes that can fit into a staged sector such that
	// bit-padding ("preprocessing") expands the file to $SECTOR_SIZE
	maxPieceSize := sb.GetMaxUserBytesPerStagedSector(1024)

	// create a piece which consumes all available space in a new, staged
	// sector
	pieceBytes := make([]byte, maxPieceSize)
	_, err = io.ReadFull(rand.Reader, pieceBytes)
	require.NoError(t, err)
	piecePath := requireTempFilePath(t, bytes.NewReader(pieceBytes))

	// generate piece commitment
	commP, err := sb.GeneratePieceCommitment(piecePath, maxPieceSize)
	require.NoError(t, err)

	// write a piece to a staged sector, reducing remaining space to 0 and
	// triggering the seal job
	sectorID, err := sb.AddPiece(ptr, "snoqualmie", maxPieceSize, piecePath)
	require.NoError(t, err)

Sidney Keese's avatar
Sidney Keese committed
54
	stagedSectors, err := sb.GetAllStagedSectors(ptr)
55
	require.NoError(t, err)
Sidney Keese's avatar
Sidney Keese committed
56
57
58
59
	require.Equal(t, 1, len(stagedSectors))
	stagedSector := stagedSectors[0]
	require.Equal(t, uint64(1), stagedSector.SectorID)

60
61
62
63
64
65
66
	// block until Groth parameter cache is (lazily) hydrated and sector has
	// been sealed (or timeout)
	status, err := pollForSectorSealingStatus(ptr, sectorID, 0, time.Minute*30)
	require.NoError(t, err)
	require.Equal(t, 1, len(status.Pieces), "expected to see the one piece we added")

	// verify the seal proof
laser's avatar
laser committed
67
	isValid, err := sb.VerifySeal(1024, status.CommR, status.CommD, status.CommRStar, [31]byte{}, sectorID, status.Proof)
68
69
70
71
72
73
74
75
76
	require.NoError(t, err)
	require.True(t, isValid)

	// verify the piece inclusion proof
	isValid, err = sb.VerifyPieceInclusionProof(1024, maxPieceSize, commP, status.CommD, status.Pieces[0].InclusionProof)
	require.NoError(t, err)
	require.True(t, isValid)

	// generate a PoSt
laser's avatar
laser committed
77
	proofs, err := sb.GeneratePoSt(ptr, [][32]byte{status.CommR}, [32]byte{}, []uint64{})
78
79
80
	require.NoError(t, err)

	// verify the PoSt
laser's avatar
laser committed
81
	isValid, err = sb.VerifyPoSt(1024, [][32]byte{status.CommR}, []uint64{status.SectorID}, [32]byte{}, proofs, []uint64{})
82
	require.NoError(t, err)
83
84
	require.True(t, isValid)

Sidney Keese's avatar
Sidney Keese committed
85
	sealedSectors, err := sb.GetAllSealedSectors(ptr)
86
	require.NoError(t, err)
Sidney Keese's avatar
Sidney Keese committed
87
88
89
90
91
	require.Equal(t, 1, len(sealedSectors), "expected to see one sealed sector")
	sealedSector := sealedSectors[0]
	require.Equal(t, uint64(1), sealedSector.SectorID)
	require.Equal(t, 1, len(sealedSector.Pieces))
	// the piece is the size of the sector, so its piece commitment should be the
Sidney Keese's avatar
Sidney Keese committed
92
	// data commitment
Sidney Keese's avatar
Sidney Keese committed
93
94
	require.Equal(t, commP, sealedSector.CommD)

95
96
97
	// unseal the sector and retrieve the client's piece, verifying that the
	// retrieved bytes match what we originally wrote to the staged sector
	unsealedPieceBytes, err := sb.ReadPieceFromSealedSector(ptr, "snoqualmie")
98
	require.NoError(t, err)
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
	require.Equal(t, pieceBytes, unsealedPieceBytes)
}

func pollForSectorSealingStatus(ptr unsafe.Pointer, sectorID uint64, sealStatusCode uint8, timeout time.Duration) (status sb.SectorSealingStatus, retErr error) {
	timeoutCh := time.After(timeout)

	tick := time.Tick(5 * time.Second)

	for {
		select {
		case <-timeoutCh:
			retErr = errors.New("timed out waiting for sector to finish sealing")
			return
		case <-tick:
			sealingStatus, err := sb.GetSectorSealingStatusByID(ptr, sectorID)
			if err != nil {
				retErr = err
				return
			}

			if sealingStatus.SealStatusCode == sealStatusCode {
				status = sealingStatus
				return
			}
		}
	}
}

func sectorIdAsBytes(sectorID uint64) [31]byte {
	slice := make([]byte, 31)
	binary.LittleEndian.PutUint64(slice, sectorID)

	var sectorIDAsBytes [31]byte
	copy(sectorIDAsBytes[:], slice)

	return sectorIDAsBytes
}

func requireTempFilePath(t *testing.T, fileContentsReader io.Reader) string {
	file, err := ioutil.TempFile("", "")
	require.NoError(t, err)

	_, err = io.Copy(file, fileContentsReader)
	require.NoError(t, err)

	return file.Name()
}

func requireTempDirPath(t *testing.T) string {
	dir, err := ioutil.TempDir("", "")
	require.NoError(t, err)

	return dir
}