diff --git a/Transfer Block.go b/Transfer Block.go index 400d19d..7b619e3 100644 --- a/Transfer Block.go +++ b/Transfer Block.go @@ -67,7 +67,7 @@ func (peer *PeerInfo) startBlockTransfer(BlockchainPublicKey *btcec.PublicKey, L udtConn.Write(blockData) sentBlocks++ - if sentBlocks >= MaxBlockSize { + if sentBlocks >= LimitBlockCount { break } } @@ -115,3 +115,44 @@ func (peer *PeerInfo) BlockTransferRequest(BlockchainPublicKey *btcec.PublicKey, return udtConn, virtualConn, nil } + +// Downloads the requested blocks for the selected blockchain from the remote peer. The callback is called for each result. +func (peer *PeerInfo) BlockDownload(BlockchainPublicKey *btcec.PublicKey, LimitBlockCount, MaxBlockSize uint64, TargetBlocks []protocol.BlockRange, callback func(data []byte, targetBlock protocol.BlockRange, blockSize uint64, availability uint8)) (err error) { + conn, _, err := peer.BlockTransferRequest(BlockchainPublicKey, LimitBlockCount, MaxBlockSize, TargetBlocks) + if err != nil { + return err + } + defer conn.Close() + + var limit uint64 + for _, target := range TargetBlocks { + limit += target.Limit + } + + for n := uint64(0); n < limit; { + data, targetBlock, blockSize, availability, err := protocol.BlockTransferReadBlock(conn, MaxBlockSize) + if err != nil { + return err + } else if !isTargetInRange(TargetBlocks, targetBlock.Offset, targetBlock.Limit) { + return errors.New("invalid returned block range") + } + + // TODO: Check if the block was already returned in case the block is available. This can be done via simple map. + + callback(data, targetBlock, blockSize, availability) + + n += targetBlock.Limit + } + + return nil +} + +func isTargetInRange(targets []protocol.BlockRange, offset, limit uint64) (valid bool) { + for _, target := range targets { + if offset >= target.Offset && offset+limit <= target.Offset+target.Limit { + return true + } + } + + return false +} diff --git a/protocol/Message Encoding Get Block.go b/protocol/Message Encoding Get Block.go index 71013e6..edb0637 100644 --- a/protocol/Message Encoding Get Block.go +++ b/protocol/Message Encoding Get Block.go @@ -29,6 +29,8 @@ Offset Size Info 2 = Block range exceeds size limit. 1 16 Block range 17 8 Block size + +The limit in block range must be 1 if a block is returned. */ package protocol @@ -197,12 +199,16 @@ func BlockTransferReadBlock(reader io.Reader, maxBlockSize uint64) (data []byte, targetBlock.Limit = binary.LittleEndian.Uint64(header[9:17]) blockSize = binary.LittleEndian.Uint64(header[17:25]) - if availability != GetBlockStatusAvailable { // return if status isn't available + if targetBlock.Limit == 0 { + return nil, targetBlock, blockSize, availability, errors.New("empty target block limit") + } else if availability != GetBlockStatusAvailable { // return if status indicates the block is not available return nil, targetBlock, blockSize, availability, nil } if blockSize > maxBlockSize { return nil, targetBlock, blockSize, availability, errors.New("remote block size exceeds limit") + } else if targetBlock.Limit != 1 { + return nil, targetBlock, blockSize, availability, errors.New("invalid target block limit") } // read the block