github.com/0xsequence/ethkit@v1.25.0/ethmonitor/bootstrap.go (about) 1 package ethmonitor 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 "github.com/0xsequence/ethkit/go-ethereum/core/types" 8 ) 9 10 // BootstrapFromBlocks will bootstrap the ethmonitor canonical chain from input blocks, 11 // while also verifying the chain hashes link together. 12 func (c *Chain) BootstrapFromBlocks(blocks []*Block) error { 13 return c.bootstrapBlocks(blocks) 14 } 15 16 // BootstrapFromBlocksJSON is convenience method which accepts json and bootstraps 17 // the ethmonitor chain. This method is here mostly for debugging purposes and recommend 18 // that you use BootstrapFromBlocks and handle constructing block events outside of ethmonitor. 19 func (c *Chain) BootstrapFromBlocksJSON(data []byte) error { 20 var blocks Blocks 21 err := json.Unmarshal(data, &blocks) 22 if err != nil { 23 return fmt.Errorf("ethmonitor: BootstrapFromBlocksJSON failed to unmarshal: %w", err) 24 } 25 return c.bootstrapBlocks(blocks) 26 } 27 28 func (c *Chain) bootstrapBlocks(blocks Blocks) error { 29 if !c.bootstrapMode { 30 return fmt.Errorf("ethmonitor: monitor must be in Bootstrap mode to use bootstrap methods") 31 } 32 if c.blocks != nil { 33 return fmt.Errorf("ethmonitor: chain has already been bootstrapped") 34 } 35 36 if len(blocks) == 0 { 37 c.blocks = make(Blocks, 0, c.retentionLimit) 38 return nil 39 } 40 41 if len(blocks) == 1 { 42 c.blocks = blocks.Copy() 43 return nil 44 } 45 46 c.blocks = make(Blocks, 0, c.retentionLimit) 47 48 if len(blocks) > c.retentionLimit { 49 blocks = blocks[len(blocks)-c.retentionLimit-1:] 50 } 51 52 for _, b := range blocks { 53 if b.Event == Added { 54 err := c.push(b) 55 if err != nil { 56 return fmt.Errorf("ethmonitor: bootstrap failed to build canonical chain: %w", err) 57 } 58 } else { 59 c.pop() 60 } 61 } 62 63 return nil 64 } 65 66 func (c *Chain) Snapshot() ([]byte, error) { 67 c.mu.Lock() 68 defer c.mu.Unlock() 69 70 data, err := json.Marshal(c.blocks) 71 if err != nil { 72 return nil, err 73 } 74 75 return data, nil 76 } 77 78 type blockSnapshot struct { 79 Block *types.Block `json:"block"` 80 Event Event `json:"event"` 81 Logs []types.Log `json:"logs"` 82 OK bool `json:"ok"` 83 } 84 85 func (b *Block) MarshalJSON() ([]byte, error) { 86 return json.Marshal(&blockSnapshot{ 87 Block: b.Block, 88 Event: b.Event, 89 Logs: b.Logs, 90 OK: b.OK, 91 }) 92 } 93 94 func (b *Block) UnmarshalJSON(data []byte) error { 95 var s *blockSnapshot 96 err := json.Unmarshal(data, &s) 97 if err != nil { 98 return err 99 } 100 b.Block = s.Block 101 b.Event = s.Event 102 b.Logs = s.Logs 103 b.OK = s.OK 104 return nil 105 }