Skip to content

Commit

Permalink
feat(): add farmer protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
n33pm committed Apr 9, 2024
1 parent 20ddb15 commit 3ad0a83
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 2 deletions.
4 changes: 2 additions & 2 deletions pkg/peerprotocol/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ func (c *Connection) Close() {
}

// Handshake performs the RPC handshake. This should be called before any other method
func (c *Connection) Handshake() error {
func (c *Connection) handshake(nodeType protocols.NodeType) error {
// Handshake
handshake := &protocols.Handshake{
NetworkID: c.networkID,
ProtocolVersion: protocols.ProtocolVersion,
SoftwareVersion: "2.0.0",
ServerPort: c.peerPort,
NodeType: protocols.NodeTypeFullNode, // I guess we're a full node
NodeType: nodeType,
Capabilities: []protocols.Capability{
{
Capability: protocols.CapabilityTypeBase,
Expand Down
37 changes: 37 additions & 0 deletions pkg/peerprotocol/farmer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package peerprotocol

import (
"github.com/chia-network/go-chia-libs/pkg/protocols"
"time"
)

// FarmerProtocol is for interfacing with full nodes via the peer protocol
type FarmerProtocol struct {
connection *Connection
}

// NewFarmerProtocol returns a new instance of the full node protocol
func NewFarmerProtocol(connection *Connection) (*FarmerProtocol, error) {
fp := &FarmerProtocol{connection: connection}

if err := fp.connection.handshake(protocols.NodeTypeFarmer); err != nil {
return nil, err
}

return fp, nil
}

// ReadSync Reads for async responses over the connection in a synchronous fashion, blocking anything else
func (c *FarmerProtocol) ReadSync(handler PeerResponseHandlerFunc) error {
return c.connection.ReadSync(handler)
}

// ReadOne reads and returns one message from the connection
func (c *FarmerProtocol) ReadOne(timeout time.Duration) (*protocols.Message, error) {
return c.connection.ReadOne(timeout)
}

// Close closes the connection
func (c *FarmerProtocol) Close() {
c.connection.Close()
}
20 changes: 20 additions & 0 deletions pkg/peerprotocol/fullnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package peerprotocol

import (
"github.com/chia-network/go-chia-libs/pkg/protocols"
"time"
)

// FullNodeProtocol is for interfacing with full nodes via the peer protocol
Expand All @@ -13,9 +14,28 @@ type FullNodeProtocol struct {
func NewFullNodeProtocol(connection *Connection) (*FullNodeProtocol, error) {
fnp := &FullNodeProtocol{connection: connection}

if err := fnp.connection.handshake(protocols.NodeTypeFullNode); err != nil {
return nil, err
}

return fnp, nil
}

// ReadSync Reads for async responses over the connection in a synchronous fashion, blocking anything else
func (c *FullNodeProtocol) ReadSync(handler PeerResponseHandlerFunc) error {
return c.connection.ReadSync(handler)
}

// ReadOne reads and returns one message from the connection
func (c *FullNodeProtocol) ReadOne(timeout time.Duration) (*protocols.Message, error) {
return c.connection.ReadOne(timeout)
}

// Close closes the connection
func (c *FullNodeProtocol) Close() {
c.connection.Close()
}

// RequestPeers asks the current peer to respond with their current peer list
func (c *FullNodeProtocol) RequestPeers() error {
return c.connection.Do(protocols.ProtocolMessageTypeRequestPeers, &protocols.RequestPeers{})
Expand Down
40 changes: 40 additions & 0 deletions pkg/protocols/farmer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package protocols

import (
"github.com/chia-network/go-chia-libs/pkg/types"
"github.com/samber/mo"
)

// SPSubSlotSourceData is the format for the sp_sub_slot_source_data response
// https://github.com/Chia-Network/chia-blockchain/blob/main/chia/protocols/farmer_protocol.py#L26
type SPSubSlotSourceData struct {
CCSubSlot types.ChallengeChainSubSlot `streamable:""`
RCSubSlot types.RewardChainSubSlot `streamable:""`
}

// SPVDFSourceData is the format for the sp_vdf_source_data response
// https://github.com/Chia-Network/chia-blockchain/blob/main/chia/protocols/farmer_protocol.py#L33
type SPVDFSourceData struct {
CCVDF types.ClassgroupElement `streamable:""`
RCVDF types.ClassgroupElement `streamable:""`
}

// NewSignagePoint is the format for the new_signage_point response
// https://github.com/Chia-Network/chia-blockchain/blob/main/chia/protocols/farmer_protocol.py#L47
type NewSignagePoint struct {
ChallengeHash types.Bytes32 `streamable:""`
ChallengeChainSP types.Bytes32 `streamable:""`
RewardChainSP types.Bytes32 `streamable:""`
Difficulty uint64 `streamable:""`
SubSlotIters uint64 `streamable:""`
SignagePointIndex uint8 `streamable:""`
PeakHeight uint32 `streamable:""`
SPSourceData mo.Option[SignagePointSourceData] `streamable:""`
}

// SignagePointSourceData is the format for the signage_point_source_data response
// https://github.com/Chia-Network/chia-blockchain/blob/main/chia/protocols/farmer_protocol.py#L40
type SignagePointSourceData struct {
SubSlotData mo.Option[SPSubSlotSourceData] `streamable:""`
VDFData mo.Option[SPVDFSourceData] `streamable:""`
}
36 changes: 36 additions & 0 deletions pkg/protocols/farmer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package protocols_test

import (
"encoding/hex"
"testing"

"github.com/stretchr/testify/assert"

"github.com/chia-network/go-chia-libs/pkg/protocols"
"github.com/chia-network/go-chia-libs/pkg/streamable"
)

func TestNewSignagePoint(t *testing.T) {
hexStr := "69171fb97a11a983e1c45f01393a0755e3b65016be6e92ea776ab8ee5b24b66a73165326a79bf653220e33573ef2cace709b31e8f9939cd9e7e7df7f009d08815c0f452f044d025bf0bb4d51744737e09723ab323731a9bbeed9c687e369ec170000000000002e0000000000228000001a004f511d0100010200661db3afacf0463587a92a3661bae6921424cbecfa6323975b102f6aa264df9e4b1c3b03bd678b5182e468d11b5a9134c8eb6534c144f9b7e56a31f3a63d8b1d8593acf1818abead01caf180c3bbf1027a32f56f441f52768f0a86ff66391a1c010000008d5d8a08d92ed62cf61288aa7043cb694cf94e49a96fe03f0d30cc01fbb10a7b5f10632cbab5fedd21e4c1c5bae92c7425fb73a5da71ec5fd426864622538b326da5bcf8f290971c1a95044e54d7fccbd9ccba2a494f6d5131221e18508c81030100"

// Hex to bytes
encodedBytes, err := hex.DecodeString(hexStr)
assert.NoError(t, err)

rp := &protocols.NewSignagePoint{}

err = streamable.Unmarshal(encodedBytes, rp)
assert.NoError(t, err)

assert.Equal(t, "69171fb97a11a983e1c45f01393a0755e3b65016be6e92ea776ab8ee5b24b66a", hex.EncodeToString(rp.ChallengeHash[:]))
assert.Equal(t, "73165326a79bf653220e33573ef2cace709b31e8f9939cd9e7e7df7f009d0881", hex.EncodeToString(rp.ChallengeChainSP[:]))
assert.Equal(t, "5c0f452f044d025bf0bb4d51744737e09723ab323731a9bbeed9c687e369ec17", hex.EncodeToString(rp.RewardChainSP[:]))
assert.Equal(t, uint64(11776), rp.Difficulty)
assert.Equal(t, uint64(578813952), rp.SubSlotIters)
assert.Equal(t, uint8(26), rp.SignagePointIndex)
assert.Equal(t, uint32(5198109), rp.PeakHeight)

assert.NotNil(t, rp.SPSourceData)

// todo test SPSourceData
}
4 changes: 4 additions & 0 deletions pkg/protocols/messagetypes.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package protocols

// ProtocolMessageType corresponds to ProtocolMessageTypes in Chia
// https://github.com/Chia-Network/chia-blockchain/blob/main/chia/protocols/protocol_message_types.py
type ProtocolMessageType uint8

const (
Expand All @@ -9,6 +10,9 @@ const (

// there are many more of these in Chia - only listing the ones current is use for now

// ProtocolMessageTypeNewSignagePoint new_signage_point
ProtocolMessageTypeNewSignagePoint ProtocolMessageType = 8

// ProtocolMessageTypeNewPeak new_peak
ProtocolMessageTypeNewPeak ProtocolMessageType = 20

Expand Down

0 comments on commit 3ad0a83

Please sign in to comment.