Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support sign keys #787

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion datasource/clickhouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ func (p *Clickhouse) Retrieve(taskIDs []common.Hash) ([]*task.Task, error) {

res = append(res, &task.Task{
ID: common.HexToHash(ts[i].TaskID),
Nonce: ts[i].Nonce,
ProjectID: pid,
ProjectVersion: ts[i].ProjectVersion,
Payload: []byte(ts[i].Payload),
DevicePubKey: pubkey,
Payload: []byte(ts[i].Payload),
Signature: sig,
})
}
Expand Down
23 changes: 14 additions & 9 deletions e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/iotexproject/w3bstream/e2e/services"
"github.com/iotexproject/w3bstream/project"
)

const (
Expand Down Expand Up @@ -80,7 +81,7 @@ func TestE2E(t *testing.T) {
require.NoError(t, err)
defer os.Remove(tempApiNodeDB.Name())
defer tempApiNodeDB.Close()
apiNode, apiNodeUrl, err := apiNodeInit(chDSN, tempApiNodeDB.Name(), chainEndpoint, contracts.TaskManager, contracts.IoID)
apiNode, apiNodeUrl, err := apiNodeInit(chDSN, tempApiNodeDB.Name(), chainEndpoint, contracts)
require.NoError(t, err)
err = apiNode.Start()
require.NoError(t, err)
Expand Down Expand Up @@ -136,15 +137,16 @@ func TestE2E(t *testing.T) {
registerIoID(t, chainEndpoint, contracts, deviceKey, projectID)

t.Run("RISC0", func(t *testing.T) {
risc0ProjectFilePath := "./testdata/risc0"
t.Cleanup(func() {
if err := risc0VMContainer.Terminate(context.Background()); err != nil {
t.Logf("failed to terminate vm container: %v", err)
}
})
risc0CodePath := "./testdata/risc0.code"
project := &project.Project{Configs: []*project.Config{{Version: "v1", VMTypeID: 1}}}

// Upload project
uploadProject(t, chainEndpoint, ipfsEndpoint, risc0ProjectFilePath, contracts, projectOwnerKey, projectID, false)
uploadProject(t, chainEndpoint, ipfsEndpoint, project, &risc0CodePath, nil, contracts, projectOwnerKey, projectID, false)
require.NoError(t, err)

// Wait a few seconds for the device info synced on api node
Expand All @@ -165,19 +167,21 @@ func TestE2E(t *testing.T) {
dataJson, err := json.Marshal(msgData)
require.NoError(t, err)

sendMessage(t, dataJson, projectID, deviceKey, apiNodeUrl)
sendMessage(t, dataJson, projectID, nil, deviceKey, apiNodeUrl)
})

t.Run("GNARK", func(t *testing.T) {
gnarkProjectFilePath := "./testdata/gnark"
t.Cleanup(func() {
if err := gnarkVMContainer.Terminate(context.Background()); err != nil {
t.Logf("failed to terminate vm container: %v", err)
}
})
gnarkCodePath := "./testdata/gnark.code"
gnarkMetadataPath := "./testdata/gnark.metadata"
project := &project.Project{Configs: []*project.Config{{Version: "v1", VMTypeID: 5}}}

// Upload project
uploadProject(t, chainEndpoint, ipfsEndpoint, gnarkProjectFilePath, contracts, projectOwnerKey, projectID, true)
uploadProject(t, chainEndpoint, ipfsEndpoint, project, &gnarkCodePath, &gnarkMetadataPath, contracts, projectOwnerKey, projectID, true)
require.NoError(t, err)

// Wait a few seconds for the device info synced on api node
Expand All @@ -187,12 +191,13 @@ func TestE2E(t *testing.T) {
data, err := hex.DecodeString("00000001000000010000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001")
require.NoError(t, err)

sendMessage(t, data, projectID, deviceKey, apiNodeUrl)
sendMessage(t, data, projectID, nil, deviceKey, apiNodeUrl)
})
}

func sendMessage(t *testing.T, dataJson []byte, projectID *big.Int, deviceKey *ecdsa.PrivateKey, apiNodeUrl string) {
reqBody, err := signMesssage(dataJson, projectID.Uint64(), deviceKey)
func sendMessage(t *testing.T, dataJson []byte, projectID *big.Int,
projectConfig *project.Config, deviceKey *ecdsa.PrivateKey, apiNodeUrl string) {
reqBody, err := signMesssage(dataJson, projectID.Uint64(), projectConfig, deviceKey)
require.NoError(t, err)

taskID, err := createTask(reqBody, apiNodeUrl)
Expand Down
40 changes: 30 additions & 10 deletions e2e/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"log/slog"
"math/big"
"os"
"testing"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand All @@ -18,6 +17,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/iotexproject/w3bstream/e2e/services"
wsproject "github.com/iotexproject/w3bstream/project"
"github.com/iotexproject/w3bstream/service/apinode"
apinodeconfig "github.com/iotexproject/w3bstream/service/apinode/config"
apinodedb "github.com/iotexproject/w3bstream/service/apinode/db"
Expand All @@ -39,7 +39,7 @@ import (
"github.com/iotexproject/w3bstream/util/ipfs"
)

func apiNodeInit(chDSN, dbFile, chainEndpoint, taskManagerContractAddr, ioidContractAddr string) (*apinode.APINode, string, error) {
func apiNodeInit(chDSN, dbFile, chainEndpoint string, contractDeployments *services.ContractsDeployments) (*apinode.APINode, string, error) {
cfg := apinodeconfig.Config{
LogLevel: slog.LevelInfo,
ServiceEndpoint: ":9000",
Expand All @@ -50,8 +50,9 @@ func apiNodeInit(chDSN, dbFile, chainEndpoint, taskManagerContractAddr, ioidCont
PrvKey: "",
ChainEndpoint: chainEndpoint,
BeginningBlockNumber: 0,
TaskManagerContractAddr: taskManagerContractAddr,
IoIDContractAddr: ioidContractAddr,
ProjectContractAddr: contractDeployments.WSProject,
TaskManagerContractAddr: contractDeployments.TaskManager,
IoIDContractAddr: contractDeployments.IoID,
}

db, err := apinodedb.New(dbFile, chDSN)
Expand Down Expand Up @@ -197,7 +198,8 @@ func registerProject(t *testing.T, chainEndpoint string,
return newProjectID, nil
}

func uploadProject(t *testing.T, chainEndpoint, ipfsURL, projectFile string,
func uploadProject(t *testing.T, chainEndpoint, ipfsURL string,
proj *wsproject.Project, projCodePath *string, projMetadataPath *string,
contractDeployments *services.ContractsDeployments, projectOwner *ecdsa.PrivateKey, newProjectID *big.Int, pauseProject bool) {
client, err := ethclient.Dial(chainEndpoint)
require.NoError(t, err)
Expand All @@ -206,12 +208,26 @@ func uploadProject(t *testing.T, chainEndpoint, ipfsURL, projectFile string,

// Upload project file to IPFS and update project config
ipfs := ipfs.NewIPFS(ipfsURL)
content, err := os.ReadFile(projectFile)
if projCodePath != nil {
codeCID, err := ipfs.AddFile(*projCodePath)
require.NoError(t, err)
cgf, err := proj.DefaultConfig()
require.NoError(t, err)
cgf.Code = fileURL(ipfsURL, codeCID)
}
if projMetadataPath != nil {
metadataCID, err := ipfs.AddFile(*projMetadataPath)
require.NoError(t, err)
cgf, err := proj.DefaultConfig()
require.NoError(t, err)
cgf.Metadata = fileURL(ipfsURL, metadataCID)
}
projBytes, err := proj.Marshal()
projHash := sha256.Sum256(projBytes)
require.NoError(t, err)
hash256 := sha256.Sum256(content)
cid, err := ipfs.AddContent(content)
cid, err := ipfs.AddContent(projBytes)
require.NoError(t, err)
projectFileURL := fmt.Sprintf("ipfs://%s/%s", ipfsURL, cid)
projectFileURL := fileURL(ipfsURL, cid)
wsProject, err := project.NewProject(common.HexToAddress(contractDeployments.WSProject), client)
require.NoError(t, err)
tOpts, err := bind.NewKeyedTransactorWithChainID(projectOwner, chainID)
Expand All @@ -222,7 +238,7 @@ func uploadProject(t *testing.T, chainEndpoint, ipfsURL, projectFile string,
_, err = services.WaitForTransactionReceipt(client, tx.Hash())
require.NoError(t, err)
}
tx, err := wsProject.UpdateConfig(tOpts, newProjectID, projectFileURL, hash256)
tx, err := wsProject.UpdateConfig(tOpts, newProjectID, projectFileURL, projHash)
require.NoError(t, err)
_, err = services.WaitForTransactionReceipt(client, tx.Hash())
require.NoError(t, err)
Expand All @@ -232,6 +248,10 @@ func uploadProject(t *testing.T, chainEndpoint, ipfsURL, projectFile string,
require.NoError(t, err)
}

func fileURL(ipfsURL, cid string) string {
return fmt.Sprintf("ipfs://%s/%s", ipfsURL, cid)
}

func registerIoID(t *testing.T, chainEndpoint string,
contractDeployments *services.ContractsDeployments, device *ecdsa.PrivateKey, projectID *big.Int) {
client, err := ethclient.Dial(chainEndpoint)
Expand Down
2 changes: 1 addition & 1 deletion e2e/services/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func SetupRisc0VM() (*VMContainer, string, error) {
func SetupGnarkVM() (*VMContainer, string, error) {
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "ghcr.io/iotexproject/gnarkserver:v0.0.17",
Image: "ghcr.io/iotexproject/gnarkserver:v0.0.20",
ExposedPorts: []string{"4005/tcp"},
WaitingFor: wait.ForListeningPort("4005"),
}
Expand Down
10 changes: 0 additions & 10 deletions e2e/testdata/gnark

This file was deleted.

Binary file added e2e/testdata/gnark.code
Binary file not shown.
Binary file added e2e/testdata/gnark.metadata
Binary file not shown.
10 changes: 0 additions & 10 deletions e2e/testdata/risc0

This file was deleted.

Binary file added e2e/testdata/risc0.code
Binary file not shown.
38 changes: 23 additions & 15 deletions e2e/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"crypto/ecdsa"
"crypto/sha256"
"encoding/binary"
"encoding/json"
"fmt"
"log"
Expand All @@ -19,13 +20,16 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/iotexproject/w3bstream/e2e/services"
"github.com/iotexproject/w3bstream/service/apinode/api"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"

"github.com/iotexproject/w3bstream/e2e/services"
"github.com/iotexproject/w3bstream/project"
"github.com/iotexproject/w3bstream/service/apinode/api"
)

func signMesssage(data []byte, projectID uint64, key *ecdsa.PrivateKey) ([]byte, error) {
func signMesssage(data []byte, projectID uint64, cfg *project.Config, key *ecdsa.PrivateKey) ([]byte, error) {
req := &api.CreateTaskReq{
Nonce: uint64(time.Now().Unix()),
ProjectID: strconv.Itoa(int(projectID)),
Expand All @@ -38,24 +42,28 @@ func signMesssage(data []byte, projectID uint64, key *ecdsa.PrivateKey) ([]byte,
}

h := sha256.Sum256(reqJson)
// TODO: uncomment once project config can be loaded
// value := gjson.GetBytes(data, "timestamp")
// buf := new(bytes.Buffer)
// if err := binary.Write(buf, binary.LittleEndian, value.Uint()); err != nil {
// return nil, errors.New("failed to convert uint64 to bytes array")
// }
// d := []byte{}
// d = append(d, h[:]...)
// d = append(d, buf.Bytes()...)
// nh := sha256.Sum256(d)

if cfg != nil && len(cfg.SignedKeys) > 0 && gjson.ValidBytes(data) {
buf := new(bytes.Buffer)
buf.Write(h[:])
for _, key := range cfg.SignedKeys {
switch key.Type {
case "uint64":
value := gjson.GetBytes(data, key.Name)
if err := binary.Write(buf, binary.LittleEndian, uint64(value.Uint())); err != nil {
return nil, errors.New("failed to convert uint64 to bytes array")
}
}
}
h = sha256.Sum256(buf.Bytes())
}

sig, err := crypto.Sign(h[:], key)
if err != nil {
return nil, err
}
sig = sig[:len(sig)-1]

fmt.Printf("signature: %s, hash: %s\n", hexutil.Encode(sig), hexutil.Encode(h[:]))

req.Signature = hexutil.Encode(sig)

return json.Marshal(req)
Expand Down
Loading
Loading