Skip to content

Commit 31d35c6

Browse files
authored
Merge branch 'main' into feature/fixCheckOldBlockIds
2 parents 66de32f + d26c18f commit 31d35c6

File tree

4 files changed

+875
-324
lines changed

4 files changed

+875
-324
lines changed

docs/howto/addingNewProtobufServices.md

Lines changed: 138 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,24 @@ To start, you’ll need to define your new service or message by creating or mod
1313
For example, to add a new RPC method in `subtreevalidation_api.proto`:
1414

1515
```proto
16-
service SubtreeValidationService {
17-
rpc ValidateSubtree (SubtreeValidationRequest) returns (SubtreeValidationResponse);
18-
rpc NewValidationEndpoint (NewValidationRequest) returns (NewValidationResponse); // New RPC method
16+
service SubtreeValidationAPI {
17+
rpc CheckSubtreeFromBlock (CheckSubtreeFromBlockRequest) returns (CheckSubtreeFromBlockResponse) {};
18+
rpc NewValidationEndpoint (NewValidationRequest) returns (NewValidationResponse) {}; // New RPC method
1919
}
2020
2121
message NewValidationRequest {
22-
string data = 1;
22+
string data = 1;
2323
}
2424
2525
message NewValidationResponse {
26-
bool success = 1;
27-
string message = 2;
26+
bool success = 1;
27+
string message = 2;
2828
}
2929
```
3030

31-
You can also define a completely new service and corresponding messages in a new `.proto` file, such as `services/newservice/newservice_api.proto`.
31+
**Note:** All service names in Teranode use the `API` suffix (e.g., `SubtreeValidationAPI`, `ValidatorAPI`, `BlockchainAPI`).
32+
33+
You can also define a completely new service and corresponding messages in a new `.proto` file, such as `services/newservice/newservice_api/newservice_api.proto`.
3234

3335
#### Step 2: Update the `Makefile`
3436

@@ -37,9 +39,9 @@ Once your new or modified `.proto` file is ready, you need to update the `Makefi
3739
To add a new service or dependency, follow these steps:
3840

3941
1. **Locate the `Makefile`** in the project root.
40-
2. **Add a new `protoc` command** for your new `.proto` file under the `gen` section.
42+
2. **Add a new `protoc` command** for your new `.proto` file under the `gen` target.
4143

42-
For example, if you created a new `newservice_api.proto` file in the `services/newservice/` directory, add a new `protoc` command like this:
44+
For example, if you created a new `newservice_api.proto` file in the `services/newservice/newservice_api/` directory, add a new `protoc` command like this:
4345

4446
```makefile
4547
protoc \
@@ -48,9 +50,11 @@ protoc \
4850
--go_opt=paths=source_relative \
4951
--go-grpc_out=. \
5052
--go-grpc_opt=paths=source_relative \
51-
services/newservice/newservice_api.proto
53+
services/newservice/newservice_api/newservice_api.proto
5254
```
5355

56+
**Note:** The directory structure follows the pattern `services/<service_name>/<service_name>_api/<service_name>_api.proto`.
57+
5458
This ensures that the new `.proto` file is processed and generates the corresponding Go code (both the message definitions and the gRPC stubs).
5559

5660
#### Step 3: Regenerate the Protobuf Files
@@ -69,51 +73,151 @@ This will generate the necessary Go files for all services, including the newly
6973

7074
Once the Go files have been generated, you can verify that the new service or endpoint is available by checking the generated `.pb.go` and `_grpc.pb.go` files. For instance, after adding a new method, you should see:
7175

72-
- The new RPC method in the `SubtreeValidationServiceServer` interface in the `_grpc.pb.go` file.
76+
- The new RPC method in the `SubtreeValidationAPIServer` interface in the `_grpc.pb.go` file.
7377
- The new request and response message types in the `.pb.go` file.
7478

75-
Heres what you might expect in `subtreevalidation_api_grpc.pb.go`:
79+
Here's what you might expect in `subtreevalidation_api_grpc.pb.go`:
7680

7781
```go
78-
// SubtreeValidationServiceServer is the server API for SubtreeValidationService.
79-
type SubtreeValidationServiceServer interface {
80-
ValidateSubtree(context.Context, *SubtreeValidationRequest) (*SubtreeValidationResponse, error)
81-
NewValidationEndpoint(context.Context, *NewValidationRequest) (*NewValidationResponse, error) // New RPC method
82+
// SubtreeValidationAPIServer is the server API for SubtreeValidationAPI.
83+
type SubtreeValidationAPIServer interface {
84+
CheckSubtreeFromBlock(context.Context, *CheckSubtreeFromBlockRequest) (*CheckSubtreeFromBlockResponse, error)
85+
NewValidationEndpoint(context.Context, *NewValidationRequest) (*NewValidationResponse, error) // New RPC method
8286
}
8387
```
8488

85-
#### Example: Adding a New Protobuf Dependency
89+
#### Example: Creating a Complete New Service
8690

87-
Let’s say you want to add a new `.proto` file that defines a shared data model used across several services. This file could be called `common.proto` and might look like this:
91+
When creating a new service from scratch, your `.proto` file should include all required elements. Here's a complete example for `services/newservice/newservice_api/newservice_api.proto`:
8892

8993
```proto
9094
syntax = "proto3";
9195
92-
package common;
96+
option go_package = "./;newservice_api";
97+
98+
package newservice_api;
99+
100+
import "google/protobuf/timestamp.proto";
101+
102+
// NewServiceAPI provides methods for the new service functionality
103+
service NewServiceAPI {
104+
// HealthGRPC checks the service's health status
105+
rpc HealthGRPC (EmptyMessage) returns (HealthResponse) {}
106+
107+
// ProcessData performs the main service operation
108+
rpc ProcessData (ProcessDataRequest) returns (ProcessDataResponse) {}
109+
}
110+
111+
// EmptyMessage represents an empty message structure used for health check requests
112+
message EmptyMessage {}
113+
114+
// HealthResponse encapsulates the service health status information
115+
message HealthResponse {
116+
bool ok = 1;
117+
string details = 2;
118+
google.protobuf.Timestamp timestamp = 3;
119+
}
93120
94-
message CommonMessage {
95-
string id = 1;
96-
string content = 2;
121+
// ProcessDataRequest defines the input for data processing
122+
message ProcessDataRequest {
123+
string data = 1;
124+
}
125+
126+
// ProcessDataResponse contains the processing result
127+
message ProcessDataResponse {
128+
bool success = 1;
129+
string result = 2;
97130
}
98131
```
99132

100-
To add this new `common.proto` file to your project and make it available to other services, follow these steps:
133+
**Key elements to include:**
101134

102-
1. **Add the `common.proto` file** to the `model` or `shared` directory (or another appropriate location).
103-
2. **Update the `Makefile`** by adding a `protoc` command to generate the Go files for `common.proto`.
135+
- `syntax = "proto3";` - Specifies the protobuf version
136+
- `option go_package = "./;newservice_api";` - Required for Go code generation
137+
- `package newservice_api;` - Package name matching the directory structure
138+
- Import statements for dependencies (e.g., `google/protobuf/timestamp.proto`)
139+
- Service definition with `API` suffix
140+
- Common patterns like `HealthGRPC` endpoint (present in all services)
141+
- Comprehensive comments for all messages and RPC methods
104142

105-
For example:
106-
```makefile
107-
protoc \
108-
--proto_path=. \
109-
--go_out=. \
110-
--go_opt=paths=source_relative \
111-
model/common.proto
143+
#### Example: Using Shared Protobuf Models
144+
145+
Teranode already provides shared data models in `model/model.proto` that can be used across services. To use these in your new service:
146+
147+
1. **Import the model** in your service's `.proto` file:
148+
149+
```proto
150+
import "model/model.proto";
151+
```
152+
153+
2. **Reference the model types** in your messages:
154+
155+
```proto
156+
message MyServiceRequest {
157+
model.MiningCandidate candidate = 1;
158+
string additional_data = 2;
159+
}
160+
```
161+
162+
If you need to add new shared models, update `model/model.proto` directly. The Makefile already includes this file in the `gen` target, so running `make gen` will regenerate the code.
163+
164+
**Existing shared proto files:**
165+
166+
- `model/model.proto` - Core data models (MiningCandidate, BlockInfo, etc.)
167+
- `errors/error.proto` - Error handling structures
168+
- `stores/utxo/status.proto` - UTXO status definitions
169+
170+
#### Step 5: Implement the Service Interface
171+
172+
After generating the protobuf files, you need to implement the service interface in your Go code. Create an implementation file (e.g., `services/newservice/service.go`):
173+
174+
```go
175+
package newservice
176+
177+
import (
178+
"context"
179+
"github.com/bsv-blockchain/teranode/services/newservice/newservice_api"
180+
"google.golang.org/protobuf/types/known/timestamppb"
181+
)
182+
183+
// Service implements the NewServiceAPIServer interface
184+
type Service struct {
185+
newservice_api.UnimplementedNewServiceAPIServer
186+
// Add your service dependencies here
187+
}
188+
189+
// NewService creates a new instance of the service
190+
func NewService() *Service {
191+
return &Service{}
192+
}
193+
194+
// HealthGRPC implements the health check endpoint
195+
func (s *Service) HealthGRPC(ctx context.Context, req *newservice_api.EmptyMessage) (*newservice_api.HealthResponse, error) {
196+
return &newservice_api.HealthResponse{
197+
Ok: true,
198+
Details: "Service is running",
199+
Timestamp: timestamppb.Now(),
200+
}, nil
201+
}
202+
203+
// ProcessData implements the main service operation
204+
func (s *Service) ProcessData(ctx context.Context, req *newservice_api.ProcessDataRequest) (*newservice_api.ProcessDataResponse, error) {
205+
// Implement your business logic here
206+
return &newservice_api.ProcessDataResponse{
207+
Success: true,
208+
Result: "Processed: " + req.Data,
209+
}, nil
210+
}
112211
```
113212

114-
This ensures that any service depending on `common.proto` can now reference the generated Go code.
213+
**Next steps:**
214+
215+
1. Register the service with the gRPC server in your main application
216+
2. Add configuration for the service in `settings.conf`
217+
3. Write unit tests for your service implementation
218+
4. Add integration tests if needed
115219

116-
#### Step 5: Cleaning Up Generated Files (Optional)
220+
#### Step 6: Cleaning Up Generated Files (Optional)
117221

118222
If you need to remove the previously generated files for some reason (e.g., during refactoring), you can use the following command:
119223

0 commit comments

Comments
 (0)