lotus/build/builtin_actors_gen_test.go
Masih H. Derkani 1d4f5397a2
Add tests to sanity-check embedded built-in actors metadata (#11684)
Add tests that assert the embedded built-in actors metadata is correct:

* the corresponding CAR file is present in built-in actors released
  assets as a CAR file.
* manifest CID is the only root CID in the corresponding CAR file.
* actor CIDs are present in the corresponding CAR file.

Fixes #11683
2024-03-06 11:38:06 +00:00

108 lines
3.5 KiB
Go

//go:build release
// +build release
package build_test
import (
"archive/tar"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"os"
"strings"
"testing"
"github.com/DataDog/zstd"
"github.com/ipfs/go-cid"
"github.com/ipld/go-car/v2"
"github.com/stretchr/testify/require"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/lotus/build"
)
func TestEmbeddedBuiltinActorsMetadata(t *testing.T) {
subjectsByVersionByNetworks := make(map[actorstypes.Version]map[string]*build.BuiltinActorsMetadata)
for _, subject := range build.EmbeddedBuiltinActorsMetadata {
if subject.BundleGitTag == "" {
// BundleGitTag is required to verify the SHA-256 checksum.
// The pack script only includes this for the latest network version, and it is good enough to only
// check the latest network version metadata. Hence the skip.
continue
}
v, ok := subjectsByVersionByNetworks[subject.Version]
if !ok {
v = make(map[string]*build.BuiltinActorsMetadata)
}
v[subject.Network] = subject
subjectsByVersionByNetworks[subject.Version] = v
}
for version, networks := range subjectsByVersionByNetworks {
cachedCar, err := os.Open(fmt.Sprintf("./actors/v%v.tar.zst", version))
require.NoError(t, err)
t.Cleanup(func() { require.NoError(t, cachedCar.Close()) })
tarReader := tar.NewReader(zstd.NewReader(cachedCar))
for {
header, err := tarReader.Next()
if errors.Is(err, io.EOF) {
break
}
require.NoError(t, err)
network := strings.TrimSuffix(strings.TrimPrefix(header.Name, "builtin-actors-"), ".car")
subject, found := networks[network]
if !found {
continue
}
shaURL := fmt.Sprintf("https://github.com/filecoin-project/builtin-actors/releases/download/%s/builtin-actors-%s.sha256", subject.BundleGitTag, subject.Network)
resp, err := http.Get(shaURL)
require.NoError(t, err, "failed to retrieve CAR SHA")
require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected response status code while retrieving CAR SHA")
respBody, err := io.ReadAll(resp.Body)
require.NoError(t, resp.Body.Close())
require.NoError(t, err)
fields := strings.Fields(string(respBody))
require.Len(t, fields, 2)
wantShaHex := fields[0]
hasher := sha256.New()
reader, err := car.NewBlockReader(io.TeeReader(tarReader, hasher))
require.NoError(t, err)
require.EqualValues(t, 1, reader.Version)
require.Len(t, reader.Roots, 1, "expected exactly one root CID for builtin actors bundle network %s, version %v", subject.Network, subject.Version)
require.True(t, reader.Roots[0].Equals(subject.ManifestCid), "manifest CID does not match")
subjectActorsByCid := make(map[cid.Cid]string)
for name, c := range subject.Actors {
subjectActorsByCid[c] = name
}
for {
next, err := reader.Next()
if errors.Is(err, io.EOF) {
break
}
require.NoError(t, err)
name, found := subjectActorsByCid[next.Cid()]
if found {
t.Logf("OK: %sv%v/%s -> %s", subject.Network, subject.Version, name, next.Cid())
delete(subjectActorsByCid, next.Cid())
}
}
require.Empty(t, subjectActorsByCid, "ZST CAR bundle did not contain CIDs for all actors; missing: %v", subjectActorsByCid)
gotShaHex := hex.EncodeToString(hasher.Sum(nil))
require.Equal(t, wantShaHex, gotShaHex, "SHA-256 digest of ZST CAR bundle does not match builtin-actors release")
delete(networks, network)
}
require.Empty(t, networks, "CAR bundle did not contain CIDs for network; missing: %v", networks)
}
}