-
Notifications
You must be signed in to change notification settings - Fork 101
/
odr_debt.go
106 lines (85 loc) · 2.61 KB
/
odr_debt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* @file
* @copyright defined in go-seele/LICENSE
*/
package light
import (
"github.com/seeleteam/go-seele/api"
"github.com/seeleteam/go-seele/common"
"github.com/seeleteam/go-seele/common/errors"
"github.com/seeleteam/go-seele/core/store"
"github.com/seeleteam/go-seele/core/types"
"github.com/seeleteam/go-seele/crypto"
)
type odrDebtRequest struct {
OdrItem
DebtHash common.Hash
}
type odrDebtResponse struct {
OdrProvableResponse
Debt *types.Debt `rlp:"nil"`
}
func (req *odrDebtRequest) code() uint16 {
return debtRequestCode
}
func (req *odrDebtRequest) handle(lp *LightProtocol) (uint16, odrResponse) {
debt, index, err := api.GetDebt(lp.debtPool, lp.chain.GetStore(), req.DebtHash)
if err != nil {
err = errors.NewStackedErrorf(err, "failed to get debt by hash %v", req.DebtHash)
return newErrorResponse(debtResponseCode, req.ReqID, err)
}
response := &odrDebtResponse{
OdrProvableResponse: OdrProvableResponse{
OdrItem: OdrItem{
ReqID: req.ReqID,
},
BlockIndex: index,
},
Debt: debt,
}
// debt is still in pool.
if response.Debt == nil || response.BlockIndex == nil {
return debtResponseCode, response
}
block, err := lp.chain.GetStore().GetBlock(response.BlockIndex.BlockHash)
if err != nil {
err = errors.NewStackedErrorf(err, "failed to get block by hash %v", response.BlockIndex.BlockHash)
return newErrorResponse(debtResponseCode, req.ReqID, err)
}
debtTrie := types.GetDebtTrie(block.Debts)
proof, err := debtTrie.GetProof(req.DebtHash.Bytes())
if err != nil {
err = errors.NewStackedError(err, "failed to get debt trie proof")
return newErrorResponse(debtResponseCode, req.ReqID, err)
}
response.Proof = mapToArray(proof)
return debtResponseCode, response
}
func (response *odrDebtResponse) validateUnpackedDebt(debtHash common.Hash) error {
if response.Debt == nil {
return nil
}
if !debtHash.Equal(response.Debt.Hash) {
return types.ErrHashMismatch
}
if !debtHash.Equal(crypto.MustHash(response.Debt.Data)) {
return types.ErrHashMismatch
}
return nil
}
func (response *odrDebtResponse) validate(request odrRequest, bcStore store.BlockchainStore) error {
header, err := response.proveHeader(bcStore)
if err != nil {
return errors.NewStackedError(err, "failed to prove block header")
}
debtHash := request.(*odrDebtRequest).DebtHash
// debt not packed yet.
if header == nil {
return response.validateUnpackedDebt(debtHash)
}
response.Debt = new(types.Debt)
if err = response.proveMerkleTrie(header.DebtHash, debtHash.Bytes(), response.Debt); err != nil {
return errors.NewStackedError(err, "failed to prove merkle trie")
}
return nil
}