diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 700be95..0b16ea1 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -14,7 +14,7 @@ jobs: - name: Get latest chiavdf libs run: | - apt-get update && apt-get install -y unzip + apt-get update && apt-get install -y unzip libgmp-dev LATEST_CHIAVDF=$(curl -s https://latest.cmm.io/chiavdf) echo "Latest chiavdf is: $LATEST_CHIAVDF" mkdir chiavdfc @@ -22,6 +22,7 @@ jobs: wget https://github.com/Chia-Network/chiavdf/releases/download/$LATEST_CHIAVDF/chiavdfc-ubuntu-intel.zip unzip chiavdfc-ubuntu-intel.zip echo "CGO_CFLAGS=-I${GITHUB_WORKSPACE}/chiavdfc/chiavdfc-ubuntu-intel" >> "$GITHUB_ENV" + echo "CGO_LDFLAGS=-L${GITHUB_WORKSPACE}/chiavdfc/chiavdfc-ubuntu-intel/static" >> "$GITHUB_ENV" - name: Test run: make test diff --git a/pkg/rpc/daemon.go b/pkg/rpc/daemon.go index f6f4866..151b0a5 100644 --- a/pkg/rpc/daemon.go +++ b/pkg/rpc/daemon.go @@ -82,3 +82,88 @@ func (s *DaemonService) GetKeys(opts *GetKeysOptions) (*GetKeysResponse, *http.R return r, resp, nil } + +// StartServiceOptions start service options +type StartServiceOptions struct { + Service ServiceFullName `json:"service"` +} + +// StartServiceResponse start service response +type StartServiceResponse struct { + Response + Service ServiceFullName `json:"service"` +} + +// StartService starts the given service +func (s *DaemonService) StartService(opts *StartServiceOptions) (*StartServiceResponse, *http.Response, error) { + request, err := s.NewRequest("start_service", opts) + if err != nil { + return nil, nil, err + } + + r := &StartServiceResponse{} + + resp, err := s.Do(request, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} + +// StopServiceOptions start service options +type StopServiceOptions struct { + Service ServiceFullName `json:"service"` +} + +// StopServiceResponse stop service response +type StopServiceResponse struct { + Response + Service ServiceFullName `json:"service"` +} + +// StopService stops the given service +func (s *DaemonService) StopService(opts *StopServiceOptions) (*StopServiceResponse, *http.Response, error) { + request, err := s.NewRequest("stop_service", opts) + if err != nil { + return nil, nil, err + } + + r := &StopServiceResponse{} + + resp, err := s.Do(request, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} + +// IsRunningOptions is service running options +type IsRunningOptions struct { + Service ServiceFullName `json:"service"` +} + +// IsRunningResponse is service running response +type IsRunningResponse struct { + Response + ServiceName ServiceFullName `json:"service_name"` + IsRunning bool `json:"is_running"` +} + +// IsRunning returns whether a service is running +func (s *DaemonService) IsRunning(opts *IsRunningOptions) (*IsRunningResponse, *http.Response, error) { + request, err := s.NewRequest("is_running", opts) + if err != nil { + return nil, nil, err + } + + r := &IsRunningResponse{} + + resp, err := s.Do(request, r) + if err != nil { + return nil, resp, err + } + + return r, resp, nil +} diff --git a/pkg/rpc/shared.go b/pkg/rpc/shared.go index 3dab056..d168c17 100644 --- a/pkg/rpc/shared.go +++ b/pkg/rpc/shared.go @@ -22,3 +22,47 @@ type GetVersionResponse struct { Response Version string `json:"version"` } + +// ServiceFullName are the full names to services that things like the daemon will recognize +type ServiceFullName string + +const ( + // ServiceFullNameDaemon name of the daemon service + ServiceFullNameDaemon ServiceFullName = "daemon" + + // ServiceFullNameDataLayer name of the data layer service + ServiceFullNameDataLayer ServiceFullName = "chia_data_layer" + + // ServiceFullNameDataLayerHTTP name of data layer http service + ServiceFullNameDataLayerHTTP ServiceFullName = "chia_data_layer_http" + + // ServiceFullNameWallet name of the wallet service + ServiceFullNameWallet ServiceFullName = "chia_wallet" + + // ServiceFullNameNode name of the full node service + ServiceFullNameNode ServiceFullName = "chia_full_node" + + // ServiceFullNameHarvester name of the harvester service + ServiceFullNameHarvester ServiceFullName = "chia_harvester" + + // ServiceFullNameFarmer name of the farmer service + ServiceFullNameFarmer ServiceFullName = "chia_farmer" + + // ServiceFullNameIntroducer name of the introducer service + ServiceFullNameIntroducer ServiceFullName = "chia_introducer" + + // ServiceFullNameTimelord name of the timelord service + ServiceFullNameTimelord ServiceFullName = "chia_timelord" + + // ServiceFullNameTimelordLauncher name of the timelord launcher service + ServiceFullNameTimelordLauncher ServiceFullName = "chia_timelord_launcher" + + // ServiceFullNameSimulator name of the simulator service + ServiceFullNameSimulator ServiceFullName = "chia_full_node_simulator" + + // ServiceFullNameSeeder name of the seeder service + ServiceFullNameSeeder ServiceFullName = "chia_seeder" + + // ServiceFullNameCrawler name of the crawler service + ServiceFullNameCrawler ServiceFullName = "chia_crawler" +) diff --git a/pkg/vdf/vdf.go b/pkg/vdf/vdf.go index 2a74a36..6ead6a0 100644 --- a/pkg/vdf/vdf.go +++ b/pkg/vdf/vdf.go @@ -2,12 +2,13 @@ package vdf /* #cgo CXXFLAGS: -std=c++17 -#cgo LDFLAGS: -lstdc++ -lchiavdfc +#cgo LDFLAGS: -lstdc++ -lchiavdfc -lgmp -lstdc++ -lm #include "c_wrapper.h" #include */ import "C" import ( + "encoding/hex" "unsafe" ) @@ -16,13 +17,16 @@ func CreateDiscriminant(seed []byte, length int) string { cSeed := C.CBytes(seed) defer C.free(cSeed) - cResultStr := C.create_discriminant_wrapper((*C.uint8_t)(cSeed), C.size_t(len(seed)), C.int(length)) - defer C.free(unsafe.Pointer(cResultStr)) + resultSize := (length + 7) / 8 + result := make([]byte, resultSize) + C.create_discriminant_wrapper( + (*C.uint8_t)(cSeed), + C.size_t(len(seed)), + C.size_t(length), + (*C.uint8_t)(unsafe.Pointer(&result[0])), + ) - // Convert the C-string to a Go string - resultStr := C.GoString(cResultStr) - - return resultStr + return hex.EncodeToString(result) } // Prove generates a proof @@ -33,7 +37,14 @@ func Prove(challengeHash []byte, initialEL []byte, discriminantSizeBits int, num cInitialEL := C.CBytes(initialEL) defer C.free(cInitialEL) - cResult := C.prove_wrapper((*C.uint8_t)(cChallengeHash), C.size_t(len(challengeHash)), (*C.uint8_t)(cInitialEL), C.size_t(len(initialEL)), C.int(discriminantSizeBits), C.uint64_t(numIterations)) + cResult := C.prove_wrapper( + (*C.uint8_t)(cChallengeHash), + C.size_t(len(challengeHash)), + (*C.uint8_t)(cInitialEL), + C.size_t(len(initialEL)), + C.size_t(discriminantSizeBits), + C.uint64_t(numIterations), + ) defer C.free(unsafe.Pointer(cResult.data)) // Convert C.ByteArray to Go []byte @@ -45,8 +56,10 @@ func Prove(challengeHash []byte, initialEL []byte, discriminantSizeBits int, num // VerifyNWesolowski checks an N Wesolowski proof. func VerifyNWesolowski(discriminant string, xS, proofBlob []byte, numIterations, discSizeBits, recursion uint64) bool { - cDiscriminant := C.CString(discriminant) - defer C.free(unsafe.Pointer(cDiscriminant)) + discriminantBytes, err := hex.DecodeString(discriminant) + if err != nil { + return false + } cXS := C.CBytes(xS) defer C.free(cXS) @@ -54,7 +67,15 @@ func VerifyNWesolowski(discriminant string, xS, proofBlob []byte, numIterations, cProofBlob := C.CBytes(proofBlob) defer C.free(cProofBlob) - result := C.verify_n_wesolowski_wrapper((*C.char)(cDiscriminant), C.size_t(len(discriminant)), (*C.char)(cXS), C.size_t(len(xS)), (*C.char)(cProofBlob), C.size_t(len(proofBlob)), C.uint64_t(numIterations), C.uint64_t(discSizeBits), C.uint64_t(recursion)) + result := C.verify_n_wesolowski_wrapper( + (*C.uint8_t)(unsafe.Pointer(&discriminantBytes[0])), + C.size_t(len(discriminantBytes)), + (*C.uchar)(cXS), + (*C.uchar)(cProofBlob), + C.size_t(len(proofBlob)), + C.uint64_t(numIterations), + C.uint64_t(recursion), + ) - return result == 1 + return bool(result) } diff --git a/pkg/vdf/vdf_test.go b/pkg/vdf/vdf_test.go new file mode 100644 index 0000000..0169c2a --- /dev/null +++ b/pkg/vdf/vdf_test.go @@ -0,0 +1,52 @@ +package vdf_test + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/chia-network/go-chia-libs/pkg/vdf" +) + +const ( + challengeHash = "885b99e5f88f762ac2af47697712050280a858ee68925cdd41d89e15e2775518" + hexSeed = "885b99e5f88f762ac2af47697712050280a858ee68925cdd41d89e15e2775518" + proofHex = "02004f5b791b1a749e07bedb221a10d4fded3c5e45586ab908753bbdd9f882f89633da35036b79956998e7755ab979eb35c7a397fa7acceb9d8f9731284dba9aa306c97b54733265e1da7d265d383f6957569fef4a11c2682de574bbc1e13a3a200901000000b1cd61a82f0f76f7a1884ecb0cb35cfc8e3213ce5e53adb67c4033bbd88159503b5da94cdeda331c63eebd94e047dde9efb76337f10a90e0f1a6ca708c40b07b65fa94d25a8a4b8070fc26c4934910bc8f109e2837d1c6f586833c2b700276410100" +) + +func TestCreateDiscriminant(t *testing.T) { + seedBytes, err := hex.DecodeString(hexSeed) + assert.NoError(t, err) + + discriminant := vdf.CreateDiscriminant(seedBytes, 1024) + + assert.Equal(t, + "fbceda79c65c7ab6a245aae6608d19bce75037784b209feb4f3715bc984384faacd1702f340a1e5fb0fad015f5232f2204e3a56196f218b53462970c23fbc1279df20a751ecba3cc4fc89d985a110809cf99b91be2852403e6d4baccfa9a805859c7729c2251c5b6ac303afdde45bbcb505dc27a8a06923809916aa7a2449c5f", + discriminant, + ) +} + +func TestVerifyNWesolowski(t *testing.T) { + seedBytes, err := hex.DecodeString(hexSeed) + assert.NoError(t, err) + + proofBytes, err := hex.DecodeString(proofHex) + assert.NoError(t, err) + + discriminant := vdf.CreateDiscriminant(seedBytes, 1024) + initialEl := append([]byte{0x08}, make([]byte, 99)...) + isValid := vdf.VerifyNWesolowski(discriminant, initialEl, proofBytes, 1<<20, 1024, 0) + assert.True(t, isValid) +} + +func TestProve(t *testing.T) { + challengeBytes, err := hex.DecodeString(challengeHash) + assert.NoError(t, err) + + initialEl := append([]byte{0x08}, make([]byte, 99)...) + proof := vdf.Prove(challengeBytes, initialEl, 1024, 1<<20) + generatedProofHex := hex.EncodeToString(proof) + + assert.Equal(t, proofHex, generatedProofHex) +}