You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

430 lines
11 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. package blocks
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "sync"
  8. "sync/atomic"
  9. "time"
  10. . "github.com/tendermint/tendermint/binary"
  11. . "github.com/tendermint/tendermint/common"
  12. db_ "github.com/tendermint/tendermint/db"
  13. "github.com/tendermint/tendermint/p2p"
  14. )
  15. var dbKeyState = []byte("state")
  16. const (
  17. blocksInfoCh = byte(0x10) // For requests & cancellations
  18. blocksDataCh = byte(0x11) // For data
  19. msgTypeUnknown = Byte(0x00)
  20. msgTypeState = Byte(0x01)
  21. msgTypeRequest = Byte(0x02)
  22. msgTypeData = Byte(0x03)
  23. )
  24. /*
  25. TODO: keep tabs on current active requests onPeerState.
  26. TODO: keep a heap of dataRequests * their corresponding timeouts.
  27. timeout dataRequests and update the peerState,
  28. TODO: when a data item has bene received successfully, update the peerState.
  29. ensure goroutine safety.
  30. */
  31. //-----------------------------------------------------------------------------
  32. const (
  33. dataTypeBlock = byte(0x00)
  34. // TODO: allow for more types, such as specific transactions
  35. )
  36. func computeDataKey(dataType byte, height uint64) string {
  37. switch dataType {
  38. case dataTypeBlock:
  39. return fmt.Sprintf("B%v", height)
  40. default:
  41. Panicf("Unknown datatype %X", dataType)
  42. return "" // should not happen
  43. }
  44. }
  45. //-----------------------------------------------------------------------------
  46. type BlockManager struct {
  47. db *db_.LevelDB
  48. sw *p2p.Switch
  49. swEvents chan interface{}
  50. state blockManagerState
  51. dataStates map[string]*dataState // TODO: replace with CMap
  52. peerStates map[string]*peerState // TODO: replace with CMap
  53. quit chan struct{}
  54. started uint32
  55. stopped uint32
  56. }
  57. func NewBlockManager(sw *p2p.Switch, db *db_.LevelDB) *BlockManager {
  58. swEvents := make(chan interface{})
  59. sw.AddEventListener("BlockManager.swEvents", swEvents)
  60. bm := &BlockManager{
  61. db: db,
  62. sw: sw,
  63. swEvents: swEvents,
  64. dataStates: make(map[string]*dataState),
  65. peerStates: make(map[string]*peerState),
  66. quit: make(chan struct{}),
  67. }
  68. bm.loadState()
  69. return bm
  70. }
  71. func (bm *BlockManager) Start() {
  72. if atomic.CompareAndSwapUint32(&bm.started, 0, 1) {
  73. log.Info("Starting BlockManager")
  74. go bm.switchEventsHandler()
  75. }
  76. }
  77. func (bm *BlockManager) Stop() {
  78. if atomic.CompareAndSwapUint32(&bm.stopped, 0, 1) {
  79. log.Info("Stopping BlockManager")
  80. close(bm.quit)
  81. close(bm.swEvents)
  82. }
  83. }
  84. // NOTE: assumes that data is already validated.
  85. // "request" is optional, it's the request response that supplied
  86. // the data.
  87. func (bm *BlockManager) StoreBlock(block *Block, origin *dataRequest) {
  88. dataKey := computeDataKey(dataTypeBlock, uint64(block.Header.Height))
  89. // Remove dataState entry, we'll no longer request this.
  90. _dataState := bm.dataStates[dataKey]
  91. removedRequests := _dataState.removeRequestsForDataType(dataTypeBlock)
  92. for _, request := range removedRequests {
  93. // Notify peer that the request has been canceled.
  94. if request.peer.Equals(origin.peer) {
  95. continue
  96. } else {
  97. // Send cancellation on blocksInfoCh channel
  98. msg := &requestMessage{
  99. dataType: Byte(dataTypeBlock),
  100. height: block.Header.Height,
  101. canceled: Byte(0x01),
  102. }
  103. tm := p2p.TypedMessage{msgTypeRequest, msg}
  104. request.peer.TrySend(blocksInfoCh, tm.Bytes())
  105. }
  106. // Remove dataRequest from request.peer's peerState.
  107. peerState := bm.peerStates[request.peer.Key]
  108. peerState.remoteDataRequest(request)
  109. }
  110. // Update state
  111. newContiguousHeight := bm.state.addData(dataTypeBlock, uint64(block.Header.Height))
  112. // If we have new data that extends our contiguous range, then announce it.
  113. if newContiguousHeight {
  114. bm.sw.Broadcast(blocksInfoCh, bm.state.stateMessage())
  115. }
  116. }
  117. func (bm *BlockManager) LoadData(dataType byte, height uint64) interface{} {
  118. panic("not yet implemented")
  119. }
  120. func (bm *BlockManager) loadState() {
  121. // Load the state
  122. stateBytes := bm.db.Get(dbKeyState)
  123. if stateBytes == nil {
  124. log.Info("New BlockManager with no state")
  125. } else {
  126. err := json.Unmarshal(stateBytes, &bm.state)
  127. if err != nil {
  128. Panicf("Could not unmarshal state bytes: %X", stateBytes)
  129. }
  130. }
  131. }
  132. func (bm *BlockManager) saveState() {
  133. stateBytes, err := json.Marshal(&bm.state)
  134. if err != nil {
  135. panic("Could not marshal state bytes")
  136. }
  137. bm.db.Set(dbKeyState, stateBytes)
  138. }
  139. // Handle peer new/done events
  140. func (bm *BlockManager) switchEventsHandler() {
  141. for {
  142. swEvent, ok := <-bm.swEvents
  143. if !ok {
  144. break
  145. }
  146. switch swEvent.(type) {
  147. case p2p.SwitchEventNewPeer:
  148. event := swEvent.(p2p.SwitchEventNewPeer)
  149. // Create entry in .peerStates
  150. bm.peerStates[event.Peer.Key] = &peerState{}
  151. // Share our state with event.Peer
  152. msg := &stateMessage{
  153. lastBlockHeight: UInt64(bm.state.lastBlockHeight),
  154. }
  155. tm := p2p.TypedMessage{msgTypeRequest, msg}
  156. event.Peer.TrySend(blocksInfoCh, tm.Bytes())
  157. case p2p.SwitchEventDonePeer:
  158. event := swEvent.(p2p.SwitchEventDonePeer)
  159. // Remove entry from .peerStates
  160. delete(bm.peerStates, event.Peer.Key)
  161. default:
  162. log.Warning("Unhandled switch event type")
  163. }
  164. }
  165. }
  166. // Handle requests from the blocks channel
  167. func (bm *BlockManager) requestsHandler() {
  168. for {
  169. inMsg, ok := bm.sw.Receive(blocksInfoCh)
  170. if !ok {
  171. // Client has stopped
  172. break
  173. }
  174. // decode message
  175. msg := decodeMessage(inMsg.Bytes)
  176. log.Info("requestHandler received %v", msg)
  177. switch msg.(type) {
  178. case *stateMessage:
  179. m := msg.(*stateMessage)
  180. peerState := bm.peerStates[inMsg.MConn.Peer.Key]
  181. if peerState == nil {
  182. continue // peer has since been disconnected.
  183. }
  184. peerState.applyStateMessage(m)
  185. // Consider requesting data.
  186. // 1. if has more validation and we want it
  187. // 2. if has more txs and we want it
  188. // if peerState.estimatedCredit() >= averageBlock
  189. // TODO: keep track of what we've requested from peer.
  190. // TODO: keep track of from which peers we've requested data.
  191. // TODO: be fair.
  192. case *requestMessage:
  193. // TODO: prevent abuse.
  194. case *dataMessage:
  195. // XXX move this to another channe
  196. // See if we want the data.
  197. // Validate data.
  198. // Add to db.
  199. // Update state & broadcast as necessary.
  200. default:
  201. // Ignore unknown message
  202. // bm.sw.StopPeerForError(inMsg.MConn.Peer, errInvalidMessage)
  203. }
  204. }
  205. // Cleanup
  206. }
  207. //-----------------------------------------------------------------------------
  208. // blockManagerState keeps track of which block parts are stored locally.
  209. // It's also persisted via JSON in the db.
  210. type blockManagerState struct {
  211. mtx sync.Mutex
  212. lastBlockHeight uint64 // Last contiguous header height
  213. otherBlockHeights map[uint64]struct{}
  214. }
  215. func (bms blockManagerState) stateMessage() *stateMessage {
  216. bms.mtx.Lock()
  217. defer bms.mtx.Unlock()
  218. return &stateMessage{
  219. lastBlockHeight: UInt64(bms.lastBlockHeight),
  220. }
  221. }
  222. func (bms blockManagerState) addData(dataType byte, height uint64) bool {
  223. bms.mtx.Lock()
  224. defer bms.mtx.Unlock()
  225. if dataType != dataTypeBlock {
  226. Panicf("Unknown datatype %X", dataType)
  227. }
  228. if bms.lastBlockHeight == height-1 {
  229. bms.lastBlockHeight = height
  230. height++
  231. for _, ok := bms.otherBlockHeights[height]; ok; {
  232. delete(bms.otherBlockHeights, height)
  233. bms.lastBlockHeight = height
  234. height++
  235. }
  236. return true
  237. }
  238. return false
  239. }
  240. //-----------------------------------------------------------------------------
  241. // dataRequest keeps track of each request for a given peice of data & peer.
  242. type dataRequest struct {
  243. peer *p2p.Peer
  244. dataType byte
  245. height uint64
  246. time time.Time // XXX keep track of timeouts.
  247. }
  248. //-----------------------------------------------------------------------------
  249. // dataState keeps track of all requests for a given piece of data.
  250. type dataState struct {
  251. mtx sync.Mutex
  252. requests []*dataRequest
  253. }
  254. func (ds *dataState) removeRequestsForDataType(dataType byte) []*dataRequest {
  255. ds.mtx.Lock()
  256. defer ds.mtx.Lock()
  257. requests := []*dataRequest{}
  258. filtered := []*dataRequest{}
  259. for _, request := range ds.requests {
  260. if request.dataType == dataType {
  261. filtered = append(filtered, request)
  262. } else {
  263. requests = append(requests, request)
  264. }
  265. }
  266. ds.requests = requests
  267. return filtered
  268. }
  269. //-----------------------------------------------------------------------------
  270. type peerState struct {
  271. mtx sync.Mutex
  272. lastBlockHeight uint64 // Last contiguous header height
  273. }
  274. func (ps *peerState) applyStateMessage(msg *stateMessage) {
  275. ps.mtx.Lock()
  276. defer ps.mtx.Unlock()
  277. ps.lastBlockHeight = uint64(msg.lastBlockHeight)
  278. }
  279. func (ps *peerState) addDataRequest(request *dataRequest) {
  280. // TODO: keep track of dataRequests
  281. }
  282. func (ps *peerState) remoteDataRequest(request *dataRequest) {
  283. // TODO: keep track of dataRequests, and remove them here.
  284. }
  285. //-----------------------------------------------------------------------------
  286. /* Messages */
  287. // TODO: check for unnecessary extra bytes at the end.
  288. func decodeMessage(bz ByteSlice) (msg interface{}) {
  289. // log.Debug("decoding msg bytes: %X", bz)
  290. switch Byte(bz[0]) {
  291. case msgTypeState:
  292. return &stateMessage{}
  293. case msgTypeRequest:
  294. return readRequestMessage(bytes.NewReader(bz[1:]))
  295. case msgTypeData:
  296. return readDataMessage(bytes.NewReader(bz[1:]))
  297. default:
  298. return nil
  299. }
  300. }
  301. /*
  302. A stateMessage declares what (contiguous) blocks & headers are known.
  303. */
  304. type stateMessage struct {
  305. lastBlockHeight UInt64 // Last contiguous block height
  306. }
  307. func readStateMessage(r io.Reader) *stateMessage {
  308. return &stateMessage{
  309. lastBlockHeight: ReadUInt64(r),
  310. }
  311. }
  312. func (m *stateMessage) WriteTo(w io.Writer) (n int64, err error) {
  313. n, err = WriteTo(msgTypeState, w, n, err)
  314. n, err = WriteTo(m.lastBlockHeight, w, n, err)
  315. return
  316. }
  317. func (m *stateMessage) String() string {
  318. return fmt.Sprintf("[State B:%v]", m.lastBlockHeight)
  319. }
  320. /*
  321. A requestMessage requests a block and/or header at a given height.
  322. */
  323. type requestMessage struct {
  324. dataType Byte
  325. height UInt64
  326. canceled Byte // 0x00 if request, 0x01 if cancellation
  327. }
  328. func readRequestMessage(r io.Reader) *requestMessage {
  329. return &requestMessage{
  330. dataType: ReadByte(r),
  331. height: ReadUInt64(r),
  332. canceled: ReadByte(r),
  333. }
  334. }
  335. func (m *requestMessage) WriteTo(w io.Writer) (n int64, err error) {
  336. n, err = WriteTo(msgTypeRequest, w, n, err)
  337. n, err = WriteTo(m.dataType, w, n, err)
  338. n, err = WriteTo(m.height, w, n, err)
  339. n, err = WriteTo(m.canceled, w, n, err)
  340. return
  341. }
  342. func (m *requestMessage) String() string {
  343. if m.canceled == Byte(0x01) {
  344. return fmt.Sprintf("[Cancellation %X@%v]", m.dataType, m.height)
  345. } else {
  346. return fmt.Sprintf("[Request %X@%v]", m.dataType, m.height)
  347. }
  348. }
  349. /*
  350. A dataMessage contains block data, maybe requested.
  351. The data can be a Validation, Txs, or whole Block object.
  352. */
  353. type dataMessage struct {
  354. dataType Byte
  355. height UInt64
  356. bytes ByteSlice
  357. }
  358. func readDataMessage(r io.Reader) *dataMessage {
  359. dataType := ReadByte(r)
  360. height := ReadUInt64(r)
  361. bytes := ReadByteSlice(r)
  362. return &dataMessage{
  363. dataType: dataType,
  364. height: height,
  365. bytes: bytes,
  366. }
  367. }
  368. func (m *dataMessage) WriteTo(w io.Writer) (n int64, err error) {
  369. n, err = WriteTo(msgTypeData, w, n, err)
  370. n, err = WriteTo(m.dataType, w, n, err)
  371. n, err = WriteTo(m.height, w, n, err)
  372. n, err = WriteTo(m.bytes, w, n, err)
  373. return
  374. }
  375. func (m *dataMessage) String() string {
  376. return fmt.Sprintf("[Data %X@%v]", m.dataType, m.height)
  377. }