Skip to content

Latest commit

 

History

History
181 lines (141 loc) · 6.34 KB

README.md

File metadata and controls

181 lines (141 loc) · 6.34 KB

ergo-core

Toy working example client code available here.

Establishing connections to the node

sequenceDiagram
    Client-->>Node: Establish TCP connection
    Node->>Client: Handshake
    Client->>Node: Handhake
    Note over Client,Node: Message exchange started
Loading

Connect to peer 📞

First connect to peer node and get Handshake message.

For the rest of the guide assume the message body as byteBuffer.

import org.ergoplatform.network.HandshakeSerializer

{ byteBuffer =>
  val handshake = HandshakeSerializer.parseBytesTry(byteBuffer)
}

Handshake 🤝

After getting and successfully reading Handshake message from peer, the peer expects to receive the Handshake back

Create PeerSpec and all parameters (including features) PeerSpec's doc:

* Declared information about peer
  *
  * @param agentName       - Network agent name. May contain information about client code
  *                        stack, starting from core code-base up to the end graphical interface.
  *                        Basic format is `/Name:Version(comments)/Name:Version/.../`,
  *                        e.g. `/Ergo-Scala-client:2.0.0(iPad; U; CPU OS 3_2_1)/AndroidBuild:0.8/`
  * @param protocolVersion - Identifies protocol version being used by the node
  * @param nodeName        - Custom node name
  * @param declaredAddress - Public network address of the node if any
  * @param features        - Set of node capabilities
import org.ergoplatform.network.PeerSpec
import org.ergoplatform.network.Version
import java.net.InetSocketAddress

val mySpec = PeerSpec(
  agentName = "morphicus",
  protocolVersion = Version("version of the ergo-core library"),
  nodeName = "ToTheMoon",
  // required for non-local communication
  declaredAddress = Some(InetSocketAddress("tothemoon.ergo", "5016")),
  // note [1]
  features = Seq.empty
)

[1] All the available peer features PeerFeatureDescriptors

Create Handshake message with peer spec and UNIX time of the message

import org.ergoplatform.network.Handshake
import org.ergoplatform.network.PeerSpec
import org.ergoplatform.network.HandshakeSerializer

val handshakeMessage = Handshake(mySpec, System.currentTimeMillis())
val handshakeMessageSerialized = HandshakeSerializer.toBytes(handshakeMessage)

Serialize the message and send it. If the message arrived successfully, start communicating with the peer node.

All communication is wrapped with message headers. Format described here. MessageBase interface to implement.

Syncing with the node

sequenceDiagram
    Client-->>Node: SyncInfo( empty )
    Node->>Client: InvData
    Client-->Client: Checking local db
    Client-->>Node: RequestModifiers( InvData )
    Node->>Client: ModifiersData
    Client-->Client: Checking PoW
    Note over Client,Node: Client verified N headers
    Client-->>Node: SyncInfo( List of N headers )
    Node->>Client: InvData( with succeeding headers )
    Note over Client,Node: Repeat
Loading

The peer node will start sending SyncInfo messages to us, since it is checking for new block information. Our client is syncing instead.

With empty lastHeaders so the node knows client is just beginning to sync.

import org.ergoplatform.nodeView.history.ErgoSyncInfoV2
import org.ergoplatform.nodeView.history.ErgoSyncInfoMessageSpec

val syncMessage = ErgoSyncInfoV2(Seq())
val syncMessageSerialized = ErgoSyncInfoMessageSpec.toBytes(syncMessage)

Node replies with InvData message, containing youngest headers id's the node has. Here the client checks if it has the headers already verified in its local db. The semantics of this is out of the tutorial scope.

Reply with RequestModifier message containing InvData the peer node sent previous.

import org.ergoplatform.network.message.InvSpec
import org.ergoplatform.network.message.RequestModifierSpec

{ byteBuffer =>
  val invData = InvSpec.parseBytesTry(byteBuffer)
  val message = RequestModifierSpec.toBytes(invData)
}

Now received ModifiersData with block data.

Checking the PoW headers 🕵️

Before adding those blocks to local database, check the headers.

import org.ergoplatform.network.message.ModifiersSpec
import org.ergoplatform.modifiers.history.header.HeaderSerializer

{ byteBuffer =>
  val data = ModifiersSpec.parseBytes(byteBuffer)
  val blockDataVerified = data.modifiers.map((id, bytes) =>
    (id, HeaderSerializer.parseBytes(bytes))
  )
}

If successful, blockDataVerified contains the map with Headers of block data. Cheers 🙌

Checking NiPoPoW proofs

What is NiPoPoW

Request NiPoPoW proof 🛸

import org.ergoplatform.network.message.{GetNipopowProofSpec, NipopowProofData}
import org.ergoplatform.nodeView.history.ErgoHistoryUtils.{P2PNipopowProofM, P2PNipopowProofK}

val nipopowRequest = GetNipopowProofSpec.toBytes(
  NipopowProofData(
    m = P2PNipopowProofM,
    k = P2PNipopowProofK,
    None
  )
)

Received the NipopowProofSpec message.

Verify NiPoPoW proof 🦾

Need to have chainSettings in order to make a nipopoSerializer instance.

import org.ergoplatform.modifiers.history.popow.{NipopowAlgos, NipopowProofSerializer}
import org.ergoplatform.network.message.NipopowProofSpec

lazy val nipopowAlgos: NipopowAlgos = new NipopowAlgos(chainSettings)
lazy val nipopowSerializer = new NipopowProofSerializer(nipopowAlgos)

{ byteBuffer =>
  val data = NipopowProofSpec.parseBytes(byteBuffer)
  val proofData = nipopowSerializer.parseBytes(data)
}

If successful, proofData.isValid will be true. Cheers 👽