-
Notifications
You must be signed in to change notification settings - Fork 0
/
contract_warp_handler.go
135 lines (118 loc) · 4.51 KB
/
contract_warp_handler.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// (c) 2023, Lux Partners Limited. All rights reserved.
// See the file LICENSE for licensing terms.
package warp
import (
"fmt"
"github.com/luxdefi/node/utils/set"
"github.com/luxdefi/node/vms/platformvm/warp"
"github.com/luxdefi/node/vms/platformvm/warp/payload"
"github.com/luxdefi/coreth/precompile/contract"
"github.com/luxdefi/coreth/predicate"
"github.com/luxdefi/coreth/vmerrs"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)
var (
_ messageHandler = addressedPayloadHandler{}
_ messageHandler = blockHashHandler{}
)
var (
getVerifiedWarpMessageInvalidOutput []byte
getVerifiedWarpBlockHashInvalidOutput []byte
)
func init() {
res, err := PackGetVerifiedWarpMessageOutput(GetVerifiedWarpMessageOutput{Valid: false})
if err != nil {
panic(err)
}
getVerifiedWarpMessageInvalidOutput = res
res, err = PackGetVerifiedWarpBlockHashOutput(GetVerifiedWarpBlockHashOutput{Valid: false})
if err != nil {
panic(err)
}
getVerifiedWarpBlockHashInvalidOutput = res
}
type messageHandler interface {
packFailed() []byte
handleMessage(msg *warp.Message) ([]byte, error)
}
func handleWarpMessage(accessibleState contract.AccessibleState, input []byte, suppliedGas uint64, handler messageHandler) ([]byte, uint64, error) {
remainingGas, err := contract.DeductGas(suppliedGas, GetVerifiedWarpMessageBaseCost)
if err != nil {
return nil, remainingGas, err
}
warpIndexInput, err := UnpackGetVerifiedWarpMessageInput(input)
if err != nil {
return nil, remainingGas, fmt.Errorf("%w: %s", errInvalidIndexInput, err)
}
if warpIndexInput > math.MaxInt32 {
return nil, remainingGas, fmt.Errorf("%w: larger than MaxInt32", errInvalidIndexInput)
}
warpIndex := int(warpIndexInput) // This conversion is safe even if int is 32 bits because we checked above.
state := accessibleState.GetStateDB()
predicateBytes, exists := state.GetPredicateStorageSlots(ContractAddress, warpIndex)
predicateResults := accessibleState.GetBlockContext().GetPredicateResults(state.GetTxHash(), ContractAddress)
valid := exists && !set.BitsFromBytes(predicateResults).Contains(warpIndex)
if !valid {
return handler.packFailed(), remainingGas, nil
}
// Note: we charge for the size of the message during both predicate verification and each time the message is read during
// EVM execution because each execution incurs an additional read cost.
msgBytesGas, overflow := math.SafeMul(GasCostPerWarpMessageBytes, uint64(len(predicateBytes)))
if overflow {
return nil, 0, vmerrs.ErrOutOfGas
}
if remainingGas, err = contract.DeductGas(remainingGas, msgBytesGas); err != nil {
return nil, 0, err
}
// Note: since the predicate is verified in advance of execution, the precompile should not
// hit an error during execution.
unpackedPredicateBytes, err := predicate.UnpackPredicate(predicateBytes)
if err != nil {
return nil, remainingGas, fmt.Errorf("%w: %s", errInvalidPredicateBytes, err)
}
warpMessage, err := warp.ParseMessage(unpackedPredicateBytes)
if err != nil {
return nil, remainingGas, fmt.Errorf("%w: %s", errInvalidWarpMsg, err)
}
res, err := handler.handleMessage(warpMessage)
if err != nil {
return nil, remainingGas, err
}
return res, remainingGas, nil
}
type addressedPayloadHandler struct{}
func (addressedPayloadHandler) packFailed() []byte {
return getVerifiedWarpMessageInvalidOutput
}
func (addressedPayloadHandler) handleMessage(warpMessage *warp.Message) ([]byte, error) {
addressedPayload, err := payload.ParseAddressedCall(warpMessage.UnsignedMessage.Payload)
if err != nil {
return nil, fmt.Errorf("%w: %s", errInvalidAddressedPayload, err)
}
return PackGetVerifiedWarpMessageOutput(GetVerifiedWarpMessageOutput{
Message: WarpMessage{
SourceChainID: common.Hash(warpMessage.SourceChainID),
OriginSenderAddress: common.BytesToAddress(addressedPayload.SourceAddress),
Payload: addressedPayload.Payload,
},
Valid: true,
})
}
type blockHashHandler struct{}
func (blockHashHandler) packFailed() []byte {
return getVerifiedWarpBlockHashInvalidOutput
}
func (blockHashHandler) handleMessage(warpMessage *warp.Message) ([]byte, error) {
blockHashPayload, err := payload.ParseHash(warpMessage.UnsignedMessage.Payload)
if err != nil {
return nil, fmt.Errorf("%w: %s", errInvalidBlockHashPayload, err)
}
return PackGetVerifiedWarpBlockHashOutput(GetVerifiedWarpBlockHashOutput{
WarpBlockHash: WarpBlockHash{
SourceChainID: common.Hash(warpMessage.SourceChainID),
BlockHash: common.BytesToHash(blockHashPayload.Hash[:]),
},
Valid: true,
})
}