diff --git a/blockchain/sync/sync_mgr.go b/blockchain/sync/sync_mgr.go new file mode 100644 index 0000000..91c2f8e --- /dev/null +++ b/blockchain/sync/sync_mgr.go @@ -0,0 +1,173 @@ +package sync + +import ( + "bytes" + "context" + "fmt" + "strings" + "sync" + + "github.com/wealdtech/go-merkletree/keccak256" + + "github.com/wealdtech/go-merkletree" + + "github.com/sirupsen/logrus" + + "github.com/Secured-Finance/dione/node" + + "github.com/Secured-Finance/dione/node/wire" + + "github.com/libp2p/go-libp2p-core/peer" + + types2 "github.com/Secured-Finance/dione/blockchain/types" + + "github.com/Secured-Finance/dione/blockchain/pool" + gorpc "github.com/libp2p/go-libp2p-gorpc" +) + +type SyncManager interface { + Start() + + Stop() +} + +type syncManager struct { + blockPool *pool.BlockPool + wg sync.WaitGroup + ctx context.Context + ctxCancelFunc context.CancelFunc + initialSyncCompleted bool + bootstrapPeer peer.ID + rpcClient *gorpc.Client +} + +func NewSyncManager(bp *pool.BlockPool, p2pRPCClient *gorpc.Client, bootstrapPeer peer.ID) SyncManager { + ctx, cancelFunc := context.WithCancel(context.Background()) + return &syncManager{ + blockPool: bp, + ctx: ctx, + ctxCancelFunc: cancelFunc, + initialSyncCompleted: false, + bootstrapPeer: bootstrapPeer, + rpcClient: p2pRPCClient, + } +} + +func (sm *syncManager) Start() { + sm.wg.Add(1) + + sm.doInitialSync() + go sm.syncLoop() +} + +func (sm *syncManager) Stop() { + sm.ctxCancelFunc() + sm.wg.Wait() +} + +func (sm *syncManager) doInitialSync() error { + if sm.initialSyncCompleted { + return nil + } + + ourLastHeight, err := sm.blockPool.GetLatestBlockHeight() + if err == pool.ErrLatestHeightNil { + gBlock := types2.GenesisBlock() + err = sm.blockPool.StoreBlock(gBlock) // commit genesis block + if err != nil { + return err + } + } + + var reply wire.LastBlockHeightReply + err = sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "LastBlockHeight", nil, &reply) + if err != nil { + return err + } + if reply.Error != nil { + return reply.Error + } + + if reply.Height > ourLastHeight { + heightCount := reply.Height - ourLastHeight + var from uint64 + to := ourLastHeight + var receivedBlocks []types2.Block + for heightCount > 0 { + from = to + 1 + var addedVal uint64 + if heightCount < node.MaxBlockCountForRetrieving { + addedVal = heightCount + } else { + addedVal = node.MaxBlockCountForRetrieving + } + heightCount -= addedVal + to += addedVal + var getBlocksReply wire.GetBlocksReply + arg := wire.GetBlocksArg{From: from, To: to} + err = sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "GetBlocks", arg, &getBlocksReply) + if err != nil { + return err + } + receivedBlocks = append(receivedBlocks, getBlocksReply.Blocks...) + if len(getBlocksReply.FailedBlockHeights) != 0 { + logrus.Warnf("remote node is unable to retrieve block heights: %s", strings.Trim(strings.Join(strings.Fields(fmt.Sprint(getBlocksReply.FailedBlockHeights)), ", "), "[]")) + // FIXME we definitely need to handle it, because in that case our chain isn't complete! + } + } + for _, b := range receivedBlocks { + err := sm.processReceivedBlock(b) // it should process the block synchronously + if err != nil { + logrus.Warnf("unable to process block %d: %s", b.Header.Height, err.Error()) + continue + } + } + } else { + // FIXME probably we need to pick up better peer for syncing, because chain of current peer can be out-of-date as well + } + + return nil +} + +func (sm *syncManager) processReceivedBlock(block types2.Block) error { + // validate block + previousBlockHeader, err := sm.blockPool.FetchBlockHeaderByHeight(block.Header.Height - 1) + if err != nil { + return fmt.Errorf("failed to retrieve previous block %d", block.Header.Height-1) + } + if bytes.Compare(block.Header.LastHash, previousBlockHeader.Hash) != 0 { + return fmt.Errorf("block header has invalid last block hash") + } + verified, err := merkletree.VerifyProofUsing(previousBlockHeader.Hash, false, block.Header.LastHashProof, [][]byte{block.Header.Hash}, keccak256.New()) + if err != nil { + return fmt.Errorf("failed to verify last block hash merkle proof: %s", err.Error()) + } + if !verified { + return fmt.Errorf("merkle hash of current block doesn't contain hash of previous block") + } + + // check if hashes of block transactions are present in the block hash merkle tree + for _, tx := range block.Data { // FIXME we need to do something with rejected txs + if tx.MerkleProof == nil { + return fmt.Errorf("block transaction hasn't merkle proof") + } + txProofVerified, err := merkletree.VerifyProofUsing(tx.Hash, false, tx.MerkleProof, [][]byte{block.Header.Hash}, keccak256.New()) + if err != nil { + return fmt.Errorf("failed to verify tx hash merkle proof: %s", err.Error()) + } + if !txProofVerified { + return fmt.Errorf("transaction doesn't present in block hash merkle tree") + } + } + + err = sm.blockPool.StoreBlock(&block) + if err != nil { + return fmt.Errorf("failed to store block in blockpool: %s", err.Error()) + } + + return nil +} + +func (sm *syncManager) syncLoop() { + +} diff --git a/go.mod b/go.mod index a5e902f..6b84fa0 100644 --- a/go.mod +++ b/go.mod @@ -33,9 +33,10 @@ require ( github.com/jmoiron/sqlx v1.2.0 github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect github.com/klauspost/cpuid/v2 v2.0.6 // indirect - github.com/ledgerwatch/lmdb-go v1.17.8 // indirect - github.com/libp2p/go-libp2p v0.12.0 - github.com/libp2p/go-libp2p-core v0.7.0 + github.com/ledgerwatch/lmdb-go v1.17.8 + github.com/libp2p/go-libp2p v0.13.0 + github.com/libp2p/go-libp2p-core v0.8.0 + github.com/libp2p/go-libp2p-gorpc v0.1.2 github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb github.com/mattn/go-sqlite3 v1.11.0 github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20210314074952-8dd49aa599b9 diff --git a/go.sum b/go.sum index 985b752..2ad6b53 100644 --- a/go.sum +++ b/go.sum @@ -952,8 +952,9 @@ github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8= github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE= -github.com/libp2p/go-libp2p v0.12.0 h1:+xai9RQnQ9l5elFOKvp5wRyjyWisSwEx+6nU2+onpUA= github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= +github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= +github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= @@ -1013,8 +1014,9 @@ github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0 h1:4a0TMjrWNTZlNvcqxZmrMRDi/NQWrhwO2pkTuLSQ/IQ= github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.0 h1:5K3mT+64qDTKbV3yTdbMCzJ7O6wbNsavAEb8iqBvBcI= +github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= @@ -1028,6 +1030,8 @@ github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQO github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-gorpc v0.1.2 h1:jHL0F79uDVPNsflS9byf8Wk23MQ0G+r5nUnLChoUn8A= +github.com/libp2p/go-libp2p-gorpc v0.1.2/go.mod h1:ulZShaJCp3JHlBMHiA20efUmiqDECza+JvGFNXJyKdI= github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= @@ -1048,8 +1052,10 @@ github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiY github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE= -github.com/libp2p/go-libp2p-mplex v0.3.0 h1:CZyqqKP0BSGQyPLvpRQougbfXaaaJZdGgzhCpJNuNSk= github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= +github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= +github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= +github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= @@ -1115,8 +1121,9 @@ github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA= github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1 h1:UTobu+oQHGdXTOGpZ4RefuVqYoJXcT0EBtSR74m2LkI= github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= +github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -1124,8 +1131,9 @@ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MB github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0 h1:ZiBYstPamsi7y6NJZebRudUzsYmVkt998hltyLqf8+g= github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= +github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= +github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= @@ -1135,8 +1143,9 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4= github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= @@ -1146,8 +1155,10 @@ github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.4.1 h1:TJxRVPY9SjH7TNrNC80l1OJMBiWhs1qpKmeB+1Ug3xU= github.com/libp2p/go-libp2p-yamux v0.4.1/go.mod h1:FA/NjRYRVNjqOzpGuGqcruH7jAU2mYIjtKBicVOL3dc= +github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= +github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= +github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= @@ -1158,8 +1169,9 @@ github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTW github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0 h1:Ov/D+8oBlbRkjBs1R1Iua8hJ8cUfbdiW8EOdZuxcgaI= github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= +github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= @@ -1211,8 +1223,9 @@ github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y= github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw= github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= +github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= @@ -1224,6 +1237,8 @@ github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= +github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= @@ -1683,11 +1698,13 @@ github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMW github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.1.13 h1:nB3O5kBSQGjEQAcfe1aLUYuxmXdFKmYgBZhY32rQb6Q= +github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= +github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= diff --git a/node/network_service.go b/node/network_service.go new file mode 100644 index 0000000..5e65b22 --- /dev/null +++ b/node/network_service.go @@ -0,0 +1,56 @@ +package node + +import ( + "context" + + "github.com/sirupsen/logrus" + + "github.com/Secured-Finance/dione/node/wire" + + "github.com/Secured-Finance/dione/blockchain/pool" +) + +const ( + MaxBlockCountForRetrieving = 500 // we do it just like in Bitcoin +) + +type NetworkService struct { + blockpool *pool.BlockPool +} + +func NewNetworkService(bp *pool.BlockPool) *NetworkService { + return &NetworkService{ + blockpool: bp, + } +} + +func (s *NetworkService) LastBlockHeight(ctx context.Context, arg interface{}, reply *wire.LastBlockHeightReply) { + height, err := s.blockpool.GetLatestBlockHeight() + if err != nil { + reply.Error = err + return + } + reply.Height = height +} + +func (s *NetworkService) GetBlocks(ctx context.Context, arg wire.GetBlocksArg, reply *wire.GetBlocksReply) { + if arg.From > arg.To { + errText := "incorrect arguments: from > to" + reply.Error = &errText + return + } + if arg.To-arg.From > MaxBlockCountForRetrieving { + errText := "incorrect arguments: count of block for retrieving is exceeded the limit" + reply.Error = &errText + return + } + for i := arg.From; i <= arg.To; i++ { + block, err := s.blockpool.FetchBlockByHeight(i) + if err != nil { + logrus.Warnf("failed to retrieve block from blockpool with height %d", i) + reply.FailedBlockHeights = append(reply.FailedBlockHeights, i) + continue + } + reply.Blocks = append(reply.Blocks, *block) + } +} diff --git a/node/node.go b/node/node.go index 94ecbe2..108ccd4 100644 --- a/node/node.go +++ b/node/node.go @@ -9,17 +9,15 @@ import ( "os" "time" - pex "github.com/Secured-Finance/go-libp2p-pex" + gorpc "github.com/libp2p/go-libp2p-gorpc" + + "github.com/Secured-Finance/dione/blockchain/pool" + + "github.com/Secured-Finance/dione/blockchain/sync" "github.com/Secured-Finance/dione/cache" "github.com/Secured-Finance/dione/consensus" - - pubsub "github.com/libp2p/go-libp2p-pubsub" - - "github.com/Secured-Finance/dione/drand" - - "github.com/ethereum/go-ethereum/common" - "github.com/libp2p/go-libp2p-core/peer" + pubsub2 "github.com/Secured-Finance/dione/pubsub" "github.com/libp2p/go-libp2p-core/discovery" @@ -30,8 +28,6 @@ import ( "github.com/Secured-Finance/dione/rpc/filecoin" - "github.com/Secured-Finance/dione/types" - "github.com/Secured-Finance/dione/wallet" "golang.org/x/xerrors" @@ -40,11 +36,8 @@ import ( "github.com/Secured-Finance/dione/config" "github.com/Secured-Finance/dione/ethclient" - pubsub2 "github.com/Secured-Finance/dione/pubsub" - "github.com/libp2p/go-libp2p" - crypto "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/host" - "github.com/multiformats/go-multiaddr" "github.com/sirupsen/logrus" ) @@ -66,6 +59,11 @@ type Node struct { Wallet *wallet.LocalWallet Cache cache.Cache DisputeManager *consensus.DisputeManager + BlockPool *pool.BlockPool + MemPool *pool.Mempool + SyncManager sync.SyncManager + NetworkService *NetworkService + NetworkRPCHost *gorpc.Server } func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) (*Node, error) { @@ -74,12 +72,12 @@ func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTim } // initialize libp2p host - lhost, err := provideLibp2pHost(n.Config, prvKey, pexDiscoveryUpdateTime) + lhost, err := provideLibp2pHost(n.Config, prvKey) if err != nil { logrus.Fatal(err) } n.Host = lhost - logrus.Info("Started up Libp2p host!") + logrus.Info("Libp2p host has been successfully initialized!") // initialize ethereum client ethClient, err := provideEthereumClient(n.Config) @@ -87,27 +85,33 @@ func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTim logrus.Fatal(err) } n.Ethereum = ethClient - logrus.Info("Started up Ethereum client!") + logrus.Info("Ethereum client has been successfully initialized!") // initialize blockchain rpc clients err = n.setupRPCClients() if err != nil { logrus.Fatal(err) } - logrus.Info("RPC clients has successfully configured!") + logrus.Info("RPC clients has been successfully configured!") // initialize pubsub subsystem psb := providePubsubRouter(lhost, n.Config) n.PubSubRouter = psb - logrus.Info("PubSub subsystem has initialized!") + logrus.Info("PubSub subsystem has been initialized!") + + // get list of bootstrap multiaddresses + baddrs, err := provideBootstrapAddrs(n.Config) + if err != nil { + logrus.Fatal(err) + } // initialize peer discovery - peerDiscovery, err := providePeerDiscovery(n.Config, lhost, pexDiscoveryUpdateTime) + peerDiscovery, err := providePeerDiscovery(baddrs, lhost, pexDiscoveryUpdateTime) if err != nil { logrus.Fatal(err) } n.PeerDiscovery = peerDiscovery - logrus.Info("Peer discovery subsystem has initialized!") + logrus.Info("Peer discovery subsystem has been initialized!") // get private key of libp2p host rawPrivKey, err := prvKey.Raw() @@ -121,20 +125,58 @@ func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTim logrus.Fatal(err) } n.Beacon = randomBeaconNetwork - logrus.Info("Random beacon subsystem has initialized!") + logrus.Info("Random beacon subsystem has been initialized!") + + // initialize event log cache subsystem + c := provideCache(config) + n.Cache = c + logrus.Info("Event cache subsystem has initialized!") + + // == initialize blockchain modules + + // initialize blockpool database + bp, err := provideBlockPool(n.Config) + if err != nil { + logrus.Fatalf("Failed to initialize blockpool: %s", err.Error()) + } + n.BlockPool = bp + logrus.Info("Block pool database has been successfully initialized!") + + // initialize mempool + mp, err := provideMemPool(c) + if err != nil { + logrus.Fatalf("Failed to initialize mempool: %s", err.Error()) + } + n.MemPool = mp + logrus.Info("Mempool has been successfully initialized!") + + ns := provideNetworkService(bp) + n.NetworkService = ns + rpcHost := provideNetworkRPCHost(lhost) + err = rpcHost.Register(ns) + if err != nil { + logrus.Fatal(err) + } + logrus.Info("Node p2p RPC network service has been successfully initialized!") + + // initialize libp2p-gorpc client + r := provideP2PRPCClient(lhost) + + // initialize sync manager + sm, err := provideSyncManager(bp, r, baddrs[0]) // FIXME here we just pick up first bootstrap in list + if err != nil { + logrus.Fatal(err) + } + n.SyncManager = sm + logrus.Info("Blockchain synchronization subsystem has been successfully initialized!") // initialize mining subsystem miner := provideMiner(n.Host.ID(), *n.Ethereum.GetEthAddress(), n.Beacon, n.Ethereum, rawPrivKey) n.Miner = miner logrus.Info("Mining subsystem has initialized!") - // initialize event log cache subsystem - eventCache := provideEventCache(config) - n.Cache = eventCache - logrus.Info("Event cache subsystem has initialized!") - // initialize consensus subsystem - cManager := provideConsensusManager(psb, miner, ethClient, rawPrivKey, n.Config.ConsensusMinApprovals, eventCache) + cManager := provideConsensusManager(psb, miner, ethClient, rawPrivKey, n.Config.ConsensusMinApprovals, c) n.ConsensusManager = cManager logrus.Info("Consensus subsystem has initialized!") @@ -147,17 +189,20 @@ func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTim logrus.Info("Dispute subsystem has initialized!") // initialize internal eth wallet - wallet, err := provideWallet(n.Host.ID(), rawPrivKey) + w, err := provideWallet(n.Host.ID(), rawPrivKey) if err != nil { logrus.Fatal(err) } - n.Wallet = wallet + n.Wallet = w return n, nil } func (n *Node) Run(ctx context.Context) error { - n.runLibp2pAsync(ctx) + err := n.runLibp2pAsync(ctx) + if err != nil { + return err + } n.subscribeOnEthContractsAsync(ctx) for { @@ -166,8 +211,6 @@ func (n *Node) Run(ctx context.Context) error { return nil } } - - // return nil } func (n *Node) runLibp2pAsync(ctx context.Context) error { @@ -243,7 +286,7 @@ func (n *Node) subscribeOnEthContractsAsync(ctx context.Context) { logrus.Infof("Proposed new Dione task with ID: %s", event.ReqID.String()) err = n.ConsensusManager.Propose(*task) if err != nil { - logrus.Errorf("Failed to propose task: %w", err) + logrus.Errorf("Failed to propose task: %v", err) } } case <-ctx.Done(): @@ -255,64 +298,6 @@ func (n *Node) subscribeOnEthContractsAsync(ctx context.Context) { }() } -func provideEventCache(config *config.Config) cache.Cache { - var backend cache.Cache - switch config.CacheType { - case "in-memory": - backend = cache.NewInMemoryCache() - case "redis": - backend = cache.NewRedisCache(config) - default: - backend = cache.NewInMemoryCache() - } - return backend -} - -func provideDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient, pcm *consensus.PBFTConsensusManager, cfg *config.Config) (*consensus.DisputeManager, error) { - return consensus.NewDisputeManager(ctx, ethClient, pcm, cfg.Ethereum.DisputeVoteWindow) -} - -func provideMiner(peerID peer.ID, ethAddress common.Address, beacon beacon.BeaconNetworks, ethClient *ethclient.EthereumClient, privateKey []byte) *consensus.Miner { - return consensus.NewMiner(peerID, ethAddress, beacon, ethClient, privateKey) -} - -func provideBeacon(ps *pubsub.PubSub) (beacon.BeaconNetworks, error) { - networks := beacon.BeaconNetworks{} - bc, err := drand.NewDrandBeacon(config.ChainGenesis, config.TaskEpochInterval, ps) - if err != nil { - return nil, fmt.Errorf("failed to setup drand beacon: %w", err) - } - networks = append(networks, beacon.BeaconNetwork{Start: types.DrandRound(config.ChainGenesis), Beacon: bc}) - // NOTE: currently we use only one network - return networks, nil -} - -// FIXME: do we really need this? -func provideWallet(peerID peer.ID, privKey []byte) (*wallet.LocalWallet, error) { - // TODO make persistent keystore - kstore := wallet.NewMemKeyStore() - keyInfo := types.KeyInfo{ - Type: types.KTEd25519, - PrivateKey: privKey, - } - - kstore.Put(wallet.KNamePrefix+peerID.String(), keyInfo) - w, err := wallet.NewWallet(kstore) - if err != nil { - return nil, xerrors.Errorf("failed to setup wallet: %w", err) - } - return w, nil -} - -func provideEthereumClient(config *config.Config) (*ethclient.EthereumClient, error) { - ethereum := ethclient.NewEthereumClient() - err := ethereum.Initialize(&config.Ethereum) - if err != nil { - return nil, xerrors.Errorf("failed to initialize ethereum client: %v", err) - } - return ethereum, nil -} - func (n *Node) setupRPCClients() error { fc := filecoin.NewLotusClient() rpc.RegisterRPC(rtypes.RPCTypeFilecoin, map[string]func(string) ([]byte, error){ @@ -328,53 +313,6 @@ func (n *Node) setupRPCClients() error { return nil } -func providePubsubRouter(lhost host.Host, config *config.Config) *pubsub2.PubSubRouter { - return pubsub2.NewPubSubRouter(lhost, config.PubSub.ServiceTopicName, config.IsBootstrap) -} - -func provideConsensusManager(psb *pubsub2.PubSubRouter, miner *consensus.Miner, ethClient *ethclient.EthereumClient, privateKey []byte, minApprovals int, evc cache.Cache) *consensus.PBFTConsensusManager { - return consensus.NewPBFTConsensusManager(psb, minApprovals, privateKey, ethClient, miner, evc) -} - -func provideLibp2pHost(config *config.Config, privateKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) (host.Host, error) { - listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", config.ListenAddr, config.ListenPort)) - if err != nil { - return nil, xerrors.Errorf("failed to parse multiaddress: %v", err) - } - host, err := libp2p.New( - context.TODO(), - libp2p.ListenAddrs(listenMultiAddr), - libp2p.Identity(privateKey), - ) - if err != nil { - return nil, xerrors.Errorf("failed to setup libp2p host: %v", err) - } - - return host, nil -} - -func providePeerDiscovery(config *config.Config, h host.Host, pexDiscoveryUpdateTime time.Duration) (discovery.Discovery, error) { - var bootstrapMaddrs []multiaddr.Multiaddr - for _, a := range config.BootstrapNodes { - maddr, err := multiaddr.NewMultiaddr(a) - if err != nil { - return nil, xerrors.Errorf("invalid multiaddress of bootstrap node: %v", err) - } - bootstrapMaddrs = append(bootstrapMaddrs, maddr) - } - - if config.IsBootstrap { - bootstrapMaddrs = nil - } - - pexDiscovery, err := pex.NewPEXDiscovery(h, bootstrapMaddrs, pexDiscoveryUpdateTime) - if err != nil { - return nil, xerrors.Errorf("failed to setup pex pexDiscovery: %v", err) - } - - return pexDiscovery, nil -} - func Start() { configPath := flag.String("config", "", "Path to config") verbose := flag.Bool("verbose", false, "Verbose logging") @@ -391,6 +329,7 @@ func Start() { var privateKey crypto.PrivKey if cfg.IsBootstrap { + // FIXME just a little hack if _, err := os.Stat(".bootstrap_privkey"); os.IsNotExist(err) { privateKey, err = generatePrivateKey() if err != nil { @@ -399,7 +338,10 @@ func Start() { f, _ := os.Create(".bootstrap_privkey") r, _ := privateKey.Raw() - f.Write(r) + _, err = f.Write(r) + if err != nil { + logrus.Fatal(err) + } } else { pkey, _ := ioutil.ReadFile(".bootstrap_privkey") privateKey, _ = crypto.UnmarshalEd25519PrivateKey(pkey) diff --git a/node/node_dep_providers.go b/node/node_dep_providers.go new file mode 100644 index 0000000..e34b60b --- /dev/null +++ b/node/node_dep_providers.go @@ -0,0 +1,176 @@ +package node + +import ( + "context" + "fmt" + "time" + + "github.com/libp2p/go-libp2p-core/protocol" + + gorpc "github.com/libp2p/go-libp2p-gorpc" + + "github.com/Secured-Finance/dione/blockchain/sync" + + "github.com/Secured-Finance/dione/blockchain/pool" + + "github.com/Secured-Finance/dione/beacon" + "github.com/Secured-Finance/dione/cache" + "github.com/Secured-Finance/dione/config" + "github.com/Secured-Finance/dione/consensus" + "github.com/Secured-Finance/dione/drand" + "github.com/Secured-Finance/dione/ethclient" + "github.com/Secured-Finance/dione/pubsub" + "github.com/Secured-Finance/dione/types" + "github.com/Secured-Finance/dione/wallet" + pex "github.com/Secured-Finance/go-libp2p-pex" + "github.com/ethereum/go-ethereum/common" + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/discovery" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + pubsub2 "github.com/libp2p/go-libp2p-pubsub" + "github.com/multiformats/go-multiaddr" + "golang.org/x/xerrors" +) + +const ( + DioneProtocolID = protocol.ID("/dione/1.0") +) + +func provideCache(config *config.Config) cache.Cache { + var backend cache.Cache + switch config.CacheType { + case "in-memory": + backend = cache.NewInMemoryCache() + case "redis": + backend = cache.NewRedisCache(config) + default: + backend = cache.NewInMemoryCache() + } + return backend +} + +func provideDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient, pcm *consensus.PBFTConsensusManager, cfg *config.Config) (*consensus.DisputeManager, error) { + return consensus.NewDisputeManager(ctx, ethClient, pcm, cfg.Ethereum.DisputeVoteWindow) +} + +func provideMiner(peerID peer.ID, ethAddress common.Address, beacon beacon.BeaconNetworks, ethClient *ethclient.EthereumClient, privateKey []byte) *consensus.Miner { + return consensus.NewMiner(peerID, ethAddress, beacon, ethClient, privateKey) +} + +func provideBeacon(ps *pubsub2.PubSub) (beacon.BeaconNetworks, error) { + networks := beacon.BeaconNetworks{} + bc, err := drand.NewDrandBeacon(config.ChainGenesis, config.TaskEpochInterval, ps) + if err != nil { + return nil, fmt.Errorf("failed to setup drand beacon: %w", err) + } + networks = append(networks, beacon.BeaconNetwork{Start: types.DrandRound(config.ChainGenesis), Beacon: bc}) + // NOTE: currently we use only one network + return networks, nil +} + +// FIXME: do we really need this? +func provideWallet(peerID peer.ID, privKey []byte) (*wallet.LocalWallet, error) { + // TODO make persistent keystore + kstore := wallet.NewMemKeyStore() + keyInfo := types.KeyInfo{ + Type: types.KTEd25519, + PrivateKey: privKey, + } + + kstore.Put(wallet.KNamePrefix+peerID.String(), keyInfo) + w, err := wallet.NewWallet(kstore) + if err != nil { + return nil, xerrors.Errorf("failed to setup wallet: %w", err) + } + return w, nil +} + +func provideEthereumClient(config *config.Config) (*ethclient.EthereumClient, error) { + ethereum := ethclient.NewEthereumClient() + err := ethereum.Initialize(&config.Ethereum) + if err != nil { + return nil, xerrors.Errorf("failed to initialize ethereum client: %v", err) + } + return ethereum, nil +} + +func providePubsubRouter(lhost host.Host, config *config.Config) *pubsub.PubSubRouter { + return pubsub.NewPubSubRouter(lhost, config.PubSub.ServiceTopicName, config.IsBootstrap) +} + +func provideConsensusManager(psb *pubsub.PubSubRouter, miner *consensus.Miner, ethClient *ethclient.EthereumClient, privateKey []byte, minApprovals int, evc cache.Cache) *consensus.PBFTConsensusManager { + return consensus.NewPBFTConsensusManager(psb, minApprovals, privateKey, ethClient, miner, evc) +} + +func provideLibp2pHost(config *config.Config, privateKey crypto.PrivKey) (host.Host, error) { + listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", config.ListenAddr, config.ListenPort)) + if err != nil { + return nil, xerrors.Errorf("failed to parse multiaddress: %v", err) + } + host, err := libp2p.New( + context.TODO(), + libp2p.ListenAddrs(listenMultiAddr), + libp2p.Identity(privateKey), + ) + if err != nil { + return nil, xerrors.Errorf("failed to setup libp2p host: %v", err) + } + + return host, nil +} + +func provideNetworkRPCHost(h host.Host) *gorpc.Server { + return gorpc.NewServer(h, DioneProtocolID) +} + +func provideBootstrapAddrs(c *config.Config) ([]multiaddr.Multiaddr, error) { + if c.IsBootstrap { + return nil, nil + } + + var bootstrapMaddrs []multiaddr.Multiaddr + for _, a := range c.BootstrapNodes { + maddr, err := multiaddr.NewMultiaddr(a) + if err != nil { + return nil, xerrors.Errorf("invalid multiaddress of bootstrap node: %v", err) + } + bootstrapMaddrs = append(bootstrapMaddrs, maddr) + } + + return bootstrapMaddrs, nil +} + +func providePeerDiscovery(baddrs []multiaddr.Multiaddr, h host.Host, pexDiscoveryUpdateTime time.Duration) (discovery.Discovery, error) { + pexDiscovery, err := pex.NewPEXDiscovery(h, baddrs, pexDiscoveryUpdateTime) + if err != nil { + return nil, xerrors.Errorf("failed to setup pex pexDiscovery: %v", err) + } + + return pexDiscovery, nil +} + +func provideBlockPool(config *config.Config) (*pool.BlockPool, error) { + return pool.NewBlockPool(config.Blockchain.DatabasePath) +} + +func provideMemPool(c cache.Cache) (*pool.Mempool, error) { + return pool.NewMempool(c) +} + +func provideSyncManager(bp *pool.BlockPool, r *gorpc.Client, bootstrap multiaddr.Multiaddr) (sync.SyncManager, error) { + addr, err := peer.AddrInfoFromP2pAddr(bootstrap) + if err != nil { + return nil, err + } + return sync.NewSyncManager(bp, r, addr.ID), nil +} + +func provideP2PRPCClient(h host.Host) *gorpc.Client { + return gorpc.NewClient(h, DioneProtocolID) +} + +func provideNetworkService(bp *pool.BlockPool) *NetworkService { + return NewNetworkService(bp) +} diff --git a/node/wire/get_blocks.go b/node/wire/get_blocks.go new file mode 100644 index 0000000..dda8cfe --- /dev/null +++ b/node/wire/get_blocks.go @@ -0,0 +1,14 @@ +package wire + +import "github.com/Secured-Finance/dione/blockchain/types" + +type GetBlocksArg struct { + From uint64 + To uint64 +} + +type GetBlocksReply struct { + Blocks []types.Block + FailedBlockHeights []uint64 // list of block heights the node was unable to retrieve + Error *string +} diff --git a/node/wire/last_block_height.go b/node/wire/last_block_height.go new file mode 100644 index 0000000..c7ceaac --- /dev/null +++ b/node/wire/last_block_height.go @@ -0,0 +1,6 @@ +package wire + +type LastBlockHeightReply struct { + Height uint64 + Error error +}