// Copyright 2017-2021 DERO Project. All rights reserved. // Use of this source code in any form is governed by RESEARCH license. // license can be found in the LICENSE file. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 // // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package p2p import "github.com/romana/rlog" import "github.com/deroproject/derohe/config" import "github.com/deroproject/graviton" // notifies inventory func (c *Connection) ChangeSet(request ChangeList, response *Changes) (err error) { if len(request.TopoHeights) < 1 || len(request.TopoHeights) > 50 { // we are expecting 1 block or 1 tx rlog.Warnf("malformed object request received, banning peer %+v %s", request, c.logid) c.exit() return nil } c.update(&request.Common) // update common information for _, topo := range request.TopoHeights { var cbl Complete_Block blid, err := chain.Load_Block_Topological_order_at_index(topo) if err != nil { return err } bl, _ := chain.Load_BL_FROM_ID(blid) cbl.Block = bl.Serialize() for j := range bl.Tx_hashes { var tx_bytes []byte if tx_bytes, err = chain.Store.Block_tx_store.ReadTX(bl.Tx_hashes[j]); err != nil { return err } cbl.Txs = append(cbl.Txs, tx_bytes) // append all the txs } cbl.Difficulty = chain.Load_Block_Difficulty(blid).String() cbl.Cumulative_Difficulty = chain.Load_Block_Cumulative_Difficulty(blid).String() // now we must load all the changes the block has done to the state tree previous_sr, err := chain.Store.Topo_store.Read(topo - 1) if err != nil { return err } current_sr, err := chain.Store.Topo_store.Read(topo) if err != nil { return err } { // do the heavy lifting, merge all changes before this topoheight var previous_ss, current_ss *graviton.Snapshot if previous_ss, err = chain.Store.Balance_store.LoadSnapshot(previous_sr.State_Version); err == nil { if current_ss, err = chain.Store.Balance_store.LoadSnapshot(current_sr.State_Version); err == nil { if response.KeyCount == 0 { var current_balance_tree *graviton.Tree if current_balance_tree, err = current_ss.GetTree(config.BALANCE_TREE); err == nil { response.KeyCount = current_balance_tree.KeyCountEstimate() } } var changes Tree_Changes if changes, err = record_changes(previous_ss, current_ss, config.BALANCE_TREE); err == nil { cbl.Changes = append(cbl.Changes, changes) } if response.SCKeyCount == 0 { var current_sc_tree *graviton.Tree if current_sc_tree, err = current_ss.GetTree(config.SC_META); err == nil { response.SCKeyCount = current_sc_tree.KeyCountEstimate() } } if changes, err = record_changes(previous_ss, current_ss, config.SC_META); err == nil { cbl.Changes = append(cbl.Changes, changes) // now lets build all the SC changes for k := range cbl.Changes[1].Keys { var sc_data Tree_Changes //fmt.Printf("bundling SC changes %x\n", k) if sc_data, err = record_changes(previous_ss, current_ss, string(k)); err == nil { cbl.Changes = append(cbl.Changes, sc_data) } } } } } if err != nil { return err } else { } response.CBlocks = append(response.CBlocks, cbl) } } // if everything is OK, we must respond with object response fill_common(&response.Common) // fill common info return nil } // this will record all the changes func record_changes(previous_ss, current_ss *graviton.Snapshot, treename string) (changes Tree_Changes, err error) { var previous_tree, current_tree *graviton.Tree if previous_tree, err = previous_ss.GetTree(treename); err == nil { if current_tree, err = current_ss.GetTree(treename); err == nil { change_handler := func(k, v []byte) { changes.Keys = append(changes.Keys, k) changes.Values = append(changes.Values, v) } err = graviton.Diff(previous_tree, current_tree, nil, change_handler, change_handler) } } changes.TreeName = []byte(treename) return }