137 lines
4.7 KiB
Go
137 lines
4.7 KiB
Go
// 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
|
|
}
|