diff --git a/README.md b/README.md index 5805271..02eaff6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ lcp-go includes the followings: ## Dependencies -- [lcp v0.2.5](https://github.com/datachainlab/lcp/releases/tag/v0.2.5) +- [lcp v0.2.6](https://github.com/datachainlab/lcp/releases/tag/v0.2.6) - [ibc-go v7.2](https://github.com/cosmos/ibc-go/releases/tag/v7.2.0) - [yui-relayer v0.4.21](https://github.com/hyperledger-labs/yui-relayer/releases/tag/v0.4.21) diff --git a/lcp b/lcp index 7a0f269..8b97ea9 160000 --- a/lcp +++ b/lcp @@ -1 +1 @@ -Subproject commit 7a0f26906e9395f94855808202e0a5287a42b427 +Subproject commit 8b97ea90a724395d1260aadd39aa165fd8e4f9b3 diff --git a/light-clients/lcp/types/client_state.go b/light-clients/lcp/types/client_state.go index 30b1229..9c734fa 100644 --- a/light-clients/lcp/types/client_state.go +++ b/light-clients/lcp/types/client_state.go @@ -84,13 +84,6 @@ func (cs ClientState) ExportMetadata(_ sdk.KVStore) []exported.GenesisMetadata { panic("not implemented") // TODO: Implement } -func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool { - return false -} - -func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, _ exported.ClientMessage) { -} - func (cs ClientState) CheckSubstituteAndUpdateState( ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore sdk.KVStore, substituteClient exported.ClientState, @@ -157,11 +150,11 @@ func (cs ClientState) VerifyMembership( if err != nil { return err } - m, err := commitmentProof.GetELCMessage() + m, err := commitmentProof.GetMessage() if err != nil { return err } - msg, err := m.GetVerifyMembershipMessage() + msg, err := m.GetVerifyMembershipProxyMessage() if err != nil { return err } diff --git a/light-clients/lcp/types/errors.go b/light-clients/lcp/types/errors.go index e080f49..16eb7d4 100644 --- a/light-clients/lcp/types/errors.go +++ b/light-clients/lcp/types/errors.go @@ -11,4 +11,5 @@ var ( ErrProcessedTimeNotFound = sdkerrors.Register(ModuleName, 4, "processed time not found") ErrProcessedHeightNotFound = sdkerrors.Register(ModuleName, 5, "processed height not found") ErrDelayPeriodNotPassed = sdkerrors.Register(ModuleName, 6, "packet-specified delay period has not been reached") + ErrInvalidMisbehaviour = sdkerrors.Register(ModuleName, 7, "invalid misbehaviour") ) diff --git a/light-clients/lcp/types/header.go b/light-clients/lcp/types/header.go index 3e0c710..4756933 100644 --- a/light-clients/lcp/types/header.go +++ b/light-clients/lcp/types/header.go @@ -1,10 +1,13 @@ package types import ( - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "fmt" + "github.com/cosmos/ibc-go/v7/modules/core/exported" ) +type ProxyMessage interface{} + var _ exported.ClientMessage = (*UpdateClientMessage)(nil) func (UpdateClientMessage) ClientType() string { @@ -12,26 +15,40 @@ func (UpdateClientMessage) ClientType() string { } func (ucm UpdateClientMessage) GetHeight() exported.Height { - m, err := ucm.GetELCMessage() + m, err := ucm.GetProxyMessage() if err != nil { panic(err) } - return m.PostHeight + switch m := m.(type) { + case *UpdateStateProxyMessage: + return m.PostHeight + default: + panic(fmt.Errorf("unexpected message type: %T", m)) + } } func (ucm UpdateClientMessage) ValidateBasic() error { - if _, err := ucm.GetELCMessage(); err != nil { + if _, err := ucm.GetProxyMessage(); err != nil { return err } return nil } -func (ucm UpdateClientMessage) GetELCMessage() (*ELCUpdateClientMessage, error) { - m, err := EthABIDecodeHeaderedMessage(ucm.ElcMessage) +func (ucm UpdateClientMessage) GetProxyMessage() (ProxyMessage, error) { + m, err := EthABIDecodeHeaderedProxyMessage(ucm.ProxyMessage) if err != nil { return nil, err } - return m.GetUpdateClientMessage() + if m.Version != LCPMessageVersion { + return nil, fmt.Errorf("unexpected commitment version: expected=%v actual=%v", LCPMessageVersion, m.Version) + } + if m.Type == LCPMessageTypeUpdateState { + return m.GetUpdateStateProxyMessage() + } else if m.Type == LCPMessageTypeMisbehaviour { + return m.GetMisbehaviourProxyMessage() + } else { + return nil, fmt.Errorf("unexpected message type: %v", m.Type) + } } var _ exported.ClientMessage = (*RegisterEnclaveKeyMessage)(nil) @@ -40,12 +57,6 @@ func (RegisterEnclaveKeyMessage) ClientType() string { return ClientTypeLCP } -func (RegisterEnclaveKeyMessage) GetHeight() exported.Height { - // XXX: the header doesn't have height info, so return zero - // this is just workaround until this function removed - return clienttypes.ZeroHeight() -} - func (RegisterEnclaveKeyMessage) ValidateBasic() error { return nil } diff --git a/light-clients/lcp/types/lcp.pb.go b/light-clients/lcp/types/lcp.pb.go index 51e3f0c..d51c423 100644 --- a/light-clients/lcp/types/lcp.pb.go +++ b/light-clients/lcp/types/lcp.pb.go @@ -25,9 +25,9 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type UpdateClientMessage struct { - ElcMessage []byte `protobuf:"bytes,1,opt,name=elc_message,json=elcMessage,proto3" json:"elc_message,omitempty"` - Signer []byte `protobuf:"bytes,2,opt,name=signer,proto3" json:"signer,omitempty"` - Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` + ProxyMessage []byte `protobuf:"bytes,1,opt,name=proxy_message,json=proxyMessage,proto3" json:"proxy_message,omitempty"` + Signer []byte `protobuf:"bytes,2,opt,name=signer,proto3" json:"signer,omitempty"` + Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` } func (m *UpdateClientMessage) Reset() { *m = UpdateClientMessage{} } @@ -103,13 +103,14 @@ func (m *RegisterEnclaveKeyMessage) XXX_DiscardUnknown() { var xxx_messageInfo_RegisterEnclaveKeyMessage proto.InternalMessageInfo type ClientState struct { - LatestHeight types.Height `protobuf:"bytes,1,opt,name=latest_height,json=latestHeight,proto3" json:"latest_height"` - Mrenclave []byte `protobuf:"bytes,2,opt,name=mrenclave,proto3" json:"mrenclave,omitempty"` - KeyExpiration uint64 `protobuf:"varint,3,opt,name=key_expiration,json=keyExpiration,proto3" json:"key_expiration,omitempty"` + Mrenclave []byte `protobuf:"bytes,1,opt,name=mrenclave,proto3" json:"mrenclave,omitempty"` + KeyExpiration uint64 `protobuf:"varint,2,opt,name=key_expiration,json=keyExpiration,proto3" json:"key_expiration,omitempty"` + Frozen bool `protobuf:"varint,3,opt,name=frozen,proto3" json:"frozen,omitempty"` + LatestHeight types.Height `protobuf:"bytes,4,opt,name=latest_height,json=latestHeight,proto3" json:"latest_height"` // e.g. SW_HARDENING_NEEDED, CONFIGURATION_AND_SW_HARDENING_NEEDED (except "OK") - AllowedQuoteStatuses []string `protobuf:"bytes,4,rep,name=allowed_quote_statuses,json=allowedQuoteStatuses,proto3" json:"allowed_quote_statuses,omitempty"` + AllowedQuoteStatuses []string `protobuf:"bytes,5,rep,name=allowed_quote_statuses,json=allowedQuoteStatuses,proto3" json:"allowed_quote_statuses,omitempty"` // e.g. INTEL-SA-XXXXX - AllowedAdvisoryIds []string `protobuf:"bytes,5,rep,name=allowed_advisory_ids,json=allowedAdvisoryIds,proto3" json:"allowed_advisory_ids,omitempty"` + AllowedAdvisoryIds []string `protobuf:"bytes,6,rep,name=allowed_advisory_ids,json=allowedAdvisoryIds,proto3" json:"allowed_advisory_ids,omitempty"` } func (m *ClientState) Reset() { *m = ClientState{} } @@ -194,38 +195,39 @@ func init() { func init() { proto.RegisterFile("ibc/lightclients/lcp/v1/lcp.proto", fileDescriptor_69f4c398e914fe8d) } var fileDescriptor_69f4c398e914fe8d = []byte{ - // 490 bytes of a gzipped FileDescriptorProto + // 504 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x52, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0x4d, 0xda, 0x50, 0xc8, 0x26, 0xed, 0xc1, 0x54, 0x25, 0x8d, 0x90, 0xd3, 0x46, 0x42, 0xea, - 0xa5, 0x36, 0x01, 0xc4, 0x9d, 0x46, 0x91, 0x88, 0x10, 0x07, 0x5c, 0xb8, 0x70, 0xb1, 0x36, 0xeb, - 0x91, 0xb3, 0xea, 0xc6, 0x6b, 0x76, 0x27, 0x06, 0x1f, 0xf9, 0x07, 0xfc, 0xac, 0x1c, 0x7b, 0xe4, - 0x84, 0x20, 0xf9, 0x23, 0x68, 0x3f, 0xd2, 0x06, 0x4e, 0x9e, 0x79, 0xef, 0xed, 0x7c, 0x3c, 0x0f, - 0x39, 0xe7, 0x33, 0x16, 0x0b, 0x9e, 0xcf, 0x91, 0x09, 0x0e, 0x05, 0xea, 0x58, 0xb0, 0x32, 0xae, - 0x46, 0xe6, 0x13, 0x95, 0x4a, 0xa2, 0x0c, 0x9e, 0xf0, 0x19, 0x8b, 0x76, 0x25, 0x91, 0xe1, 0xaa, - 0x51, 0xff, 0x38, 0x97, 0xb9, 0xb4, 0x9a, 0xd8, 0x44, 0x4e, 0xde, 0x1f, 0x98, 0x8a, 0x4c, 0x2a, - 0x88, 0x9d, 0xdc, 0x14, 0x73, 0x91, 0x13, 0x0c, 0x05, 0x79, 0xfc, 0xa9, 0xcc, 0x28, 0xc2, 0xd8, - 0xa2, 0xef, 0x41, 0x6b, 0x9a, 0x43, 0x30, 0x20, 0x1d, 0x10, 0x2c, 0x5d, 0xb8, 0xb4, 0xd7, 0x3c, - 0x6b, 0x5e, 0x74, 0x13, 0x02, 0x82, 0x6d, 0x05, 0x27, 0xe4, 0x40, 0xf3, 0xbc, 0x00, 0xd5, 0xdb, - 0xb3, 0x9c, 0xcf, 0x82, 0xa7, 0xa4, 0x6d, 0x22, 0x8a, 0x4b, 0x05, 0xbd, 0x7d, 0x4b, 0xdd, 0x03, - 0x43, 0x24, 0xa7, 0x09, 0xe4, 0x5c, 0x23, 0xa8, 0x49, 0xc1, 0x04, 0xad, 0xe0, 0x1d, 0xd4, 0x3b, - 0x25, 0x15, 0x94, 0x52, 0xa1, 0x6d, 0xd7, 0x4e, 0x7c, 0xf6, 0x6f, 0xc9, 0xbd, 0xff, 0x4a, 0x06, - 0xe7, 0xa4, 0x6b, 0x12, 0x5e, 0xe4, 0x29, 0x03, 0x85, 0xbe, 0x67, 0xc7, 0x63, 0x63, 0x50, 0x38, - 0xfc, 0xbe, 0x47, 0x3a, 0x6e, 0xbd, 0x6b, 0xa4, 0x08, 0xc1, 0x84, 0x1c, 0x0a, 0x8a, 0xa0, 0x31, - 0x9d, 0x83, 0x71, 0xd2, 0xf6, 0xeb, 0xbc, 0xe8, 0x47, 0xc6, 0x5b, 0x63, 0x56, 0xe4, 0x2d, 0xaa, - 0x46, 0xd1, 0x5b, 0xab, 0xb8, 0x6a, 0xad, 0x7e, 0x0d, 0x1a, 0x49, 0xd7, 0x3d, 0x73, 0x98, 0x99, - 0x6b, 0xa1, 0xc0, 0xad, 0xb1, 0x9d, 0xeb, 0x0e, 0x08, 0x9e, 0x91, 0xa3, 0x1b, 0xa8, 0x53, 0xf8, - 0x56, 0x72, 0x45, 0x91, 0xcb, 0xc2, 0x4e, 0xd6, 0x4a, 0x0e, 0x6f, 0xa0, 0x9e, 0xdc, 0x81, 0xc1, - 0x2b, 0x72, 0x42, 0x85, 0x90, 0x5f, 0x21, 0x4b, 0xbf, 0x2c, 0x25, 0x42, 0xaa, 0x91, 0xe2, 0x52, - 0x83, 0xee, 0xb5, 0xce, 0xf6, 0x2f, 0xda, 0xc9, 0xb1, 0x67, 0x3f, 0x18, 0xf2, 0xda, 0x73, 0xc1, - 0x73, 0xb2, 0xc5, 0x53, 0x9a, 0x55, 0x5c, 0x4b, 0x55, 0xa7, 0x3c, 0xd3, 0xbd, 0x07, 0xf6, 0x4d, - 0xe0, 0xb9, 0x37, 0x9e, 0x9a, 0x66, 0x7a, 0x38, 0x25, 0x47, 0x63, 0x59, 0x68, 0x28, 0xf4, 0x52, - 0x3b, 0x17, 0x4e, 0xc9, 0x23, 0xd3, 0x0b, 0x52, 0x9e, 0xf9, 0xff, 0xfb, 0xd0, 0xe6, 0xd3, 0xcc, - 0x6c, 0x86, 0x7c, 0x01, 0x1a, 0xe9, 0xa2, 0xb4, 0x9b, 0xb5, 0x92, 0x7b, 0xe0, 0xea, 0xe3, 0xea, - 0x4f, 0xd8, 0x58, 0xad, 0xc3, 0xe6, 0xed, 0x3a, 0x6c, 0xfe, 0x5e, 0x87, 0xcd, 0x1f, 0x9b, 0xb0, - 0x71, 0xbb, 0x09, 0x1b, 0x3f, 0x37, 0x61, 0xe3, 0xf3, 0xeb, 0x9c, 0xe3, 0x7c, 0x39, 0x8b, 0x98, - 0x5c, 0xc4, 0x19, 0x45, 0xca, 0xe6, 0x94, 0x17, 0x82, 0xce, 0xcc, 0x0d, 0x5f, 0xe6, 0xd2, 0x9d, - 0xf7, 0xe5, 0xee, 0x7d, 0x63, 0x5d, 0x82, 0x9e, 0x1d, 0xd8, 0x7b, 0x7c, 0xf9, 0x37, 0x00, 0x00, - 0xff, 0xff, 0x59, 0x18, 0xa4, 0x73, 0x04, 0x03, 0x00, 0x00, + 0x10, 0x8d, 0xd3, 0x10, 0x9a, 0x4d, 0xd2, 0x83, 0xa9, 0x8a, 0x1b, 0x21, 0x37, 0x0d, 0x42, 0xca, + 0xa5, 0x36, 0x01, 0xc4, 0x9d, 0x46, 0x91, 0x88, 0x10, 0x07, 0x5c, 0xb8, 0x70, 0xb1, 0x36, 0xf6, + 0xe0, 0xac, 0xea, 0x78, 0xcd, 0xee, 0x24, 0xd4, 0xfc, 0x0a, 0xae, 0xfc, 0xa3, 0x1c, 0x7b, 0xe4, + 0x84, 0x20, 0xf9, 0x23, 0x68, 0x3f, 0x4a, 0x02, 0x27, 0xef, 0xbc, 0xf7, 0xf6, 0x3d, 0xef, 0xcc, + 0x90, 0x73, 0x36, 0x4b, 0xc2, 0x9c, 0x65, 0x73, 0x4c, 0x72, 0x06, 0x05, 0xca, 0x30, 0x4f, 0xca, + 0x70, 0x35, 0x52, 0x9f, 0xa0, 0x14, 0x1c, 0xb9, 0xfb, 0x90, 0xcd, 0x92, 0x60, 0x5f, 0x12, 0x28, + 0x6e, 0x35, 0xea, 0x1d, 0x67, 0x3c, 0xe3, 0x5a, 0x13, 0xaa, 0x93, 0x91, 0xf7, 0xce, 0x94, 0x63, + 0xc2, 0x05, 0x84, 0x46, 0xae, 0xcc, 0xcc, 0xc9, 0x08, 0x06, 0x25, 0x79, 0xf0, 0xa1, 0x4c, 0x29, + 0xc2, 0x58, 0xa3, 0x6f, 0x41, 0x4a, 0x9a, 0x81, 0xfb, 0x98, 0x74, 0x4b, 0xc1, 0x6f, 0xaa, 0x78, + 0x61, 0x00, 0xcf, 0xe9, 0x3b, 0xc3, 0x4e, 0xd4, 0xd1, 0xe0, 0x9d, 0xe8, 0x84, 0x34, 0x25, 0xcb, + 0x0a, 0x10, 0x5e, 0x5d, 0xb3, 0xb6, 0x72, 0x1f, 0x91, 0x96, 0x3a, 0x51, 0x5c, 0x0a, 0xf0, 0x0e, + 0x34, 0xb5, 0x03, 0x06, 0x48, 0x4e, 0x23, 0xc8, 0x98, 0x44, 0x10, 0x93, 0x22, 0xc9, 0xe9, 0x0a, + 0xde, 0xc0, 0xbe, 0xa5, 0x80, 0x92, 0x0b, 0xd4, 0x81, 0xad, 0xc8, 0x56, 0xff, 0x5a, 0xd6, 0xff, + 0xb3, 0x74, 0xcf, 0x49, 0x47, 0x15, 0xac, 0xc8, 0xe2, 0x04, 0x04, 0xda, 0xcc, 0xb6, 0xc5, 0xc6, + 0x20, 0x70, 0xf0, 0xbd, 0x4e, 0xda, 0xe6, 0x89, 0x57, 0x48, 0x11, 0x94, 0xe1, 0x42, 0x80, 0xc9, + 0xb7, 0x8f, 0xdb, 0x01, 0xee, 0x13, 0x72, 0x74, 0x0d, 0x55, 0x0c, 0x37, 0x25, 0x13, 0x14, 0x19, + 0x2f, 0x74, 0x66, 0x23, 0xea, 0x5e, 0x43, 0x35, 0xf9, 0x0b, 0xaa, 0xbf, 0xfd, 0x24, 0xf8, 0x57, + 0x28, 0x74, 0xe2, 0x61, 0x64, 0x2b, 0x77, 0x42, 0xba, 0x39, 0x45, 0x90, 0x18, 0xcf, 0x41, 0x8d, + 0xca, 0x6b, 0xf4, 0x9d, 0x61, 0xfb, 0x59, 0x2f, 0x50, 0xc3, 0x53, 0xd3, 0x08, 0xec, 0x0c, 0x56, + 0xa3, 0xe0, 0xb5, 0x56, 0x5c, 0x36, 0xd6, 0x3f, 0xcf, 0x6a, 0x51, 0xc7, 0x5c, 0x33, 0x98, 0xfb, + 0x82, 0x9c, 0xd0, 0x3c, 0xe7, 0x5f, 0x20, 0x8d, 0x3f, 0x2f, 0x39, 0x42, 0x2c, 0x91, 0xe2, 0x52, + 0x82, 0xf4, 0xee, 0xf5, 0x0f, 0x86, 0xad, 0xe8, 0xd8, 0xb2, 0xef, 0x14, 0x79, 0x65, 0x39, 0xf7, + 0x29, 0xb9, 0xc3, 0x63, 0x9a, 0xae, 0x98, 0xe4, 0xa2, 0x8a, 0x59, 0x2a, 0xbd, 0xa6, 0xbe, 0xe3, + 0x5a, 0xee, 0x95, 0xa5, 0xa6, 0xa9, 0x1c, 0x4c, 0xc9, 0xd1, 0x98, 0x17, 0x12, 0x0a, 0xb9, 0x94, + 0xa6, 0x3b, 0xa7, 0xe4, 0x50, 0x65, 0x41, 0xcc, 0x52, 0xdb, 0x9c, 0xfb, 0xba, 0x9e, 0xa6, 0xaa, + 0x71, 0xc8, 0x16, 0x20, 0x91, 0x2e, 0x4a, 0xdb, 0x95, 0x1d, 0x70, 0xf9, 0x7e, 0xfd, 0xdb, 0xaf, + 0xad, 0x37, 0xbe, 0x73, 0xbb, 0xf1, 0x9d, 0x5f, 0x1b, 0xdf, 0xf9, 0xb6, 0xf5, 0x6b, 0xb7, 0x5b, + 0xbf, 0xf6, 0x63, 0xeb, 0xd7, 0x3e, 0xbe, 0xcc, 0x18, 0xce, 0x97, 0xb3, 0x20, 0xe1, 0x8b, 0x30, + 0xa5, 0x48, 0x93, 0x39, 0x65, 0x45, 0x4e, 0x67, 0x6a, 0xbf, 0x2f, 0x32, 0x6e, 0x56, 0xff, 0x62, + 0x7f, 0xf7, 0xb1, 0x2a, 0x41, 0xce, 0x9a, 0x7a, 0x57, 0x9f, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, + 0xc0, 0x21, 0xbe, 0x1a, 0x20, 0x03, 0x00, 0x00, } func (m *UpdateClientMessage) Marshal() (dAtA []byte, err error) { @@ -262,10 +264,10 @@ func (m *UpdateClientMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.ElcMessage) > 0 { - i -= len(m.ElcMessage) - copy(dAtA[i:], m.ElcMessage) - i = encodeVarintLcp(dAtA, i, uint64(len(m.ElcMessage))) + if len(m.ProxyMessage) > 0 { + i -= len(m.ProxyMessage) + copy(dAtA[i:], m.ProxyMessage) + i = encodeVarintLcp(dAtA, i, uint64(len(m.ProxyMessage))) i-- dAtA[i] = 0xa } @@ -342,7 +344,7 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.AllowedAdvisoryIds[iNdEx]) i = encodeVarintLcp(dAtA, i, uint64(len(m.AllowedAdvisoryIds[iNdEx]))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x32 } } if len(m.AllowedQuoteStatuses) > 0 { @@ -351,31 +353,41 @@ func (m *ClientState) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.AllowedQuoteStatuses[iNdEx]) i = encodeVarintLcp(dAtA, i, uint64(len(m.AllowedQuoteStatuses[iNdEx]))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a + } + } + { + size, err := m.LatestHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLcp(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.Frozen { + i-- + if m.Frozen { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x18 } if m.KeyExpiration != 0 { i = encodeVarintLcp(dAtA, i, uint64(m.KeyExpiration)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x10 } if len(m.Mrenclave) > 0 { i -= len(m.Mrenclave) copy(dAtA[i:], m.Mrenclave) i = encodeVarintLcp(dAtA, i, uint64(len(m.Mrenclave))) i-- - dAtA[i] = 0x12 - } - { - size, err := m.LatestHeight.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintLcp(dAtA, i, uint64(size)) + dAtA[i] = 0xa } - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -431,7 +443,7 @@ func (m *UpdateClientMessage) Size() (n int) { } var l int _ = l - l = len(m.ElcMessage) + l = len(m.ProxyMessage) if l > 0 { n += 1 + l + sovLcp(uint64(l)) } @@ -473,8 +485,6 @@ func (m *ClientState) Size() (n int) { } var l int _ = l - l = m.LatestHeight.Size() - n += 1 + l + sovLcp(uint64(l)) l = len(m.Mrenclave) if l > 0 { n += 1 + l + sovLcp(uint64(l)) @@ -482,6 +492,11 @@ func (m *ClientState) Size() (n int) { if m.KeyExpiration != 0 { n += 1 + sovLcp(uint64(m.KeyExpiration)) } + if m.Frozen { + n += 2 + } + l = m.LatestHeight.Size() + n += 1 + l + sovLcp(uint64(l)) if len(m.AllowedQuoteStatuses) > 0 { for _, s := range m.AllowedQuoteStatuses { l = len(s) @@ -550,7 +565,7 @@ func (m *UpdateClientMessage) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ElcMessage", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProxyMessage", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -577,9 +592,9 @@ func (m *UpdateClientMessage) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ElcMessage = append(m.ElcMessage[:0], dAtA[iNdEx:postIndex]...) - if m.ElcMessage == nil { - m.ElcMessage = []byte{} + m.ProxyMessage = append(m.ProxyMessage[:0], dAtA[iNdEx:postIndex]...) + if m.ProxyMessage == nil { + m.ProxyMessage = []byte{} } iNdEx = postIndex case 2: @@ -852,9 +867,9 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LatestHeight", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Mrenclave", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowLcp @@ -864,30 +879,31 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthLcp } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthLcp } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.LatestHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Mrenclave = append(m.Mrenclave[:0], dAtA[iNdEx:postIndex]...) + if m.Mrenclave == nil { + m.Mrenclave = []byte{} } iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Mrenclave", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field KeyExpiration", wireType) } - var byteLen int + m.KeyExpiration = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowLcp @@ -897,31 +913,16 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + m.KeyExpiration |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { - return ErrInvalidLengthLcp - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthLcp - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Mrenclave = append(m.Mrenclave[:0], dAtA[iNdEx:postIndex]...) - if m.Mrenclave == nil { - m.Mrenclave = []byte{} - } - iNdEx = postIndex case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field KeyExpiration", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Frozen", wireType) } - m.KeyExpiration = 0 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowLcp @@ -931,12 +932,46 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.KeyExpiration |= uint64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } + m.Frozen = bool(v != 0) case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LatestHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLcp + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLcp + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLcp + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LatestHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AllowedQuoteStatuses", wireType) } @@ -968,7 +1003,7 @@ func (m *ClientState) Unmarshal(dAtA []byte) error { } m.AllowedQuoteStatuses = append(m.AllowedQuoteStatuses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 5: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AllowedAdvisoryIds", wireType) } diff --git a/light-clients/lcp/types/message.go b/light-clients/lcp/types/message.go index 46f6033..1bab1be 100644 --- a/light-clients/lcp/types/message.go +++ b/light-clients/lcp/types/message.go @@ -15,8 +15,9 @@ import ( const ( LCPMessageVersion = 1 - LCPMessageTypeUpdateClient = 1 + LCPMessageTypeUpdateState = 1 LCPMessageTypeState = 2 + LCPMessageTypeMisbehaviour = 3 ) const ( @@ -36,7 +37,7 @@ var ( {Name: "message", Type: "bytes"}, }) - updateClientMessageABI, _ = abi.NewType("tuple", "struct UpdateClientMessage", []abi.ArgumentMarshaling{ + updateStateProxyMessageABI, _ = abi.NewType("tuple", "struct UpdateStateProxyMessage", []abi.ArgumentMarshaling{ {Name: "prev_height", Type: "tuple", Components: []abi.ArgumentMarshaling{ {Name: "revision_number", Type: "uint64"}, {Name: "revision_height", Type: "uint64"}, @@ -58,6 +59,18 @@ var ( }}, }) + misbehaviourProxyMessageABI, _ = abi.NewType("tuple", "struct MisbehaviourProxyMessage", []abi.ArgumentMarshaling{ + {Name: "prev_states", Type: "tuple[]", Components: []abi.ArgumentMarshaling{ + {Name: "height", Type: "tuple", Components: []abi.ArgumentMarshaling{ + {Name: "revision_number", Type: "uint64"}, + {Name: "revision_height", Type: "uint64"}, + }}, + {Name: "state_id", Type: "bytes32"}, + }}, + {Name: "context", Type: "bytes"}, + {Name: "client_message", Type: "bytes"}, + }) + headeredMessageContextABI, _ = abi.NewType("tuple", "struct HeaderedMessageContext", []abi.ArgumentMarshaling{ {Name: "header", Type: "bytes32"}, {Name: "context_bytes", Type: "bytes"}, @@ -86,7 +99,7 @@ func (id StateID) EqualBytes(bz []byte) bool { return bytes.Equal(id[:], bz) } -type ELCUpdateClientMessage struct { +type UpdateStateProxyMessage struct { PrevHeight *clienttypes.Height PrevStateID *StateID PostHeight clienttypes.Height @@ -101,6 +114,15 @@ type EmittedState struct { State codectypes.Any } +type MisbehaviourProxyMessage struct { + PrevStates []struct { + Height clienttypes.Height + StateID StateID + } + Context ValidationContext + ClientMessage []byte +} + // ValidationContext is the interface of validation context. type ValidationContext interface { Validate(time.Time) error @@ -218,34 +240,44 @@ type CommitmentProof struct { Signature []byte } -func (p CommitmentProof) GetELCMessage() (*HeaderedELCMessage, error) { - return EthABIDecodeHeaderedMessage(p.Message) +func (p CommitmentProof) GetMessage() (*HeaderedProxyMessage, error) { + return EthABIDecodeHeaderedProxyMessage(p.Message) } -type HeaderedELCMessage struct { +type HeaderedProxyMessage struct { Version uint16 Type uint16 Message []byte } -func (c HeaderedELCMessage) GetUpdateClientMessage() (*ELCUpdateClientMessage, error) { +func (c HeaderedProxyMessage) GetUpdateStateProxyMessage() (*UpdateStateProxyMessage, error) { + if c.Version != LCPMessageVersion { + return nil, fmt.Errorf("unexpected commitment version: expected=%v actual=%v", LCPMessageVersion, c.Version) + } + if c.Type != LCPMessageTypeUpdateState { + return nil, fmt.Errorf("unexpected commitment type: expected=%v actual=%v", LCPMessageTypeUpdateState, c.Type) + } + return EthABIDecodeUpdateStateProxyMessage(c.Message) +} + +func (c HeaderedProxyMessage) GetMisbehaviourProxyMessage() (*MisbehaviourProxyMessage, error) { if c.Version != LCPMessageVersion { return nil, fmt.Errorf("unexpected commitment version: expected=%v actual=%v", LCPMessageVersion, c.Version) } - if c.Type != LCPMessageTypeUpdateClient { - return nil, fmt.Errorf("unexpected commitment type: expected=%v actual=%v", LCPMessageTypeUpdateClient, c.Type) + if c.Type != LCPMessageTypeMisbehaviour { + return nil, fmt.Errorf("unexpected commitment type: expected=%v actual=%v", LCPMessageTypeMisbehaviour, c.Type) } - return EthABIDecodeUpdateClientMessage(c.Message) + return EthABIDecodeMisbehaviourProxyMessage(c.Message) } -func (c HeaderedELCMessage) GetVerifyMembershipMessage() (*ELCVerifyMembershipMessage, error) { +func (c HeaderedProxyMessage) GetVerifyMembershipProxyMessage() (*ELCVerifyMembershipMessage, error) { if c.Version != LCPMessageVersion { return nil, fmt.Errorf("unexpected commitment version: expected=%v actual=%v", LCPMessageVersion, c.Version) } if c.Type != LCPMessageTypeState { return nil, fmt.Errorf("unexpected commitment type: expected=%v actual=%v", LCPMessageTypeState, c.Type) } - return EthABIDecodeVerifyMembershipMessage(c.Message) + return EthABIDecodeVerifyMembershipProxyMessage(c.Message) } func EthABIEncodeCommitmentProof(p *CommitmentProof) ([]byte, error) { @@ -271,7 +303,7 @@ func EthABIDecodeCommitmentProof(bz []byte) (*CommitmentProof, error) { return &p, nil } -func EthABIDecodeHeaderedMessage(bz []byte) (*HeaderedELCMessage, error) { +func EthABIDecodeHeaderedProxyMessage(bz []byte) (*HeaderedProxyMessage, error) { unpacker := abi.Arguments{ {Type: headeredMessageABI}, } @@ -290,16 +322,16 @@ func EthABIDecodeHeaderedMessage(bz []byte) (*HeaderedELCMessage, error) { // 4-31: reserved version := binary.BigEndian.Uint16(p.Header[:2]) messageType := binary.BigEndian.Uint16(p.Header[2:4]) - return &HeaderedELCMessage{ + return &HeaderedProxyMessage{ Version: version, Type: messageType, Message: p.Message, }, nil } -func EthABIDecodeUpdateClientMessage(bz []byte) (*ELCUpdateClientMessage, error) { +func EthABIDecodeUpdateStateProxyMessage(bz []byte) (*UpdateStateProxyMessage, error) { unpacker := abi.Arguments{ - {Type: updateClientMessageABI}, + {Type: updateStateProxyMessageABI}, } v, err := unpacker.Unpack(bz) if err != nil { @@ -330,7 +362,7 @@ func EthABIDecodeUpdateClientMessage(bz []byte) (*ELCUpdateClientMessage, error) if err != nil { return nil, err } - c := &ELCUpdateClientMessage{ + c := &UpdateStateProxyMessage{ PostStateID: p.PostStateId, PostHeight: clienttypes.Height{RevisionNumber: p.PostHeight.RevisionNumber, RevisionHeight: p.PostHeight.RevisionHeight}, Timestamp: p.Timestamp, @@ -356,6 +388,49 @@ func EthABIDecodeUpdateClientMessage(bz []byte) (*ELCUpdateClientMessage, error) return c, nil } +func EthABIDecodeMisbehaviourProxyMessage(bz []byte) (*MisbehaviourProxyMessage, error) { + unpacker := abi.Arguments{ + {Type: misbehaviourProxyMessageABI}, + } + v, err := unpacker.Unpack(bz) + if err != nil { + return nil, err + } + p := v[0].(struct { + PrevStates []struct { + Height struct { + RevisionNumber uint64 `json:"revision_number"` + RevisionHeight uint64 `json:"revision_height"` + } `json:"height"` + StateId [32]byte `json:"state_id"` + } `json:"prev_states"` + Context []byte `json:"context"` + ClientMessage []byte `json:"client_message"` + }) + cctx, err := EthABIDecodeValidationContext(p.Context) + if err != nil { + return nil, err + } + var prevStates []struct { + Height clienttypes.Height + StateID StateID + } + for _, prev := range p.PrevStates { + prevStates = append(prevStates, struct { + Height clienttypes.Height + StateID StateID + }{ + Height: clienttypes.Height{RevisionNumber: prev.Height.RevisionNumber, RevisionHeight: prev.Height.RevisionHeight}, + StateID: prev.StateId, + }) + } + return &MisbehaviourProxyMessage{ + PrevStates: prevStates, + Context: cctx, + ClientMessage: p.ClientMessage, + }, nil +} + func EthABIDecodeValidationContext(bz []byte) (ValidationContext, error) { unpacker := abi.Arguments{ {Type: headeredMessageContextABI}, @@ -404,7 +479,7 @@ func EthABIDecodeTrustingPeriodValidationContext(bz []byte) (*TrustingPeriodVali return DecodeTrustingPeriodValidationContext(p.Timestamps, p.Params), nil } -func EthABIDecodeVerifyMembershipMessage(bz []byte) (*ELCVerifyMembershipMessage, error) { +func EthABIDecodeVerifyMembershipProxyMessage(bz []byte) (*ELCVerifyMembershipMessage, error) { unpacker := abi.Arguments{ {Type: verifyMembershipMessageABI}, } diff --git a/light-clients/lcp/types/message_test.go b/light-clients/lcp/types/message_test.go index d71ef0d..e3b1c46 100644 --- a/light-clients/lcp/types/message_test.go +++ b/light-clients/lcp/types/message_test.go @@ -23,18 +23,18 @@ func TestVerifyMembershipABI(t *testing.T) { if !bytes.Equal(bz, bz2) { t.Fatal("pack/unpack failed") } - hc, err := EthABIDecodeHeaderedMessage(proof.Message) + hc, err := EthABIDecodeHeaderedProxyMessage(proof.Message) if err != nil { t.Fatal(err) } - _, err = hc.GetVerifyMembershipMessage() + _, err = hc.GetVerifyMembershipProxyMessage() if err != nil { t.Fatal(err) } } } -func TestUpdateClientMessageABI(t *testing.T) { +func TestUpdateStateProxyMessageABI(t *testing.T) { for _, tc := range testUpdateClientMessageABICases { bz, err := hex.DecodeString(tc.input) if err != nil { @@ -51,11 +51,28 @@ func TestUpdateClientMessageABI(t *testing.T) { if !bytes.Equal(bz, bz2) { t.Fatal("pack/unpack failed") } - hc, err := EthABIDecodeHeaderedMessage(proof.Message) + hc, err := EthABIDecodeHeaderedProxyMessage(proof.Message) if err != nil { t.Fatal(err) } - _, err = hc.GetUpdateClientMessage() + _, err = hc.GetUpdateStateProxyMessage() + if err != nil { + t.Fatal(err) + } + } +} + +func TestMisbehaviourProxyMessageABI(t *testing.T) { + for _, tc := range testMisbehaviourMessageABICases { + bz, err := hex.DecodeString(tc.input) + if err != nil { + t.Fatal(err) + } + hc, err := EthABIDecodeHeaderedProxyMessage(bz) + if err != nil { + t.Fatal(err) + } + _, err = hc.GetMisbehaviourProxyMessage() if err != nil { t.Fatal(err) } @@ -266,3 +283,14 @@ var testUpdateClientMessageABICases = []struct { {"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000001d8eec843c18f10befcd290a502412f987e36e90000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000000000000000020000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055c770df405e715d0000000000000000000000000000000000000000000000006b1b7c3ccefe39ff70724658b322b1c3b73f012dfccc60e7836f4551c2f1bf502d3f6a4255ff7df000000000000000000000000000000000000000000000000af6531c1b64ff11e50000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000001d424418357aea168000000000000000650093b481e6d9ffe000000000000000318c4fdf912bdf16d000000000000000a9f2ae83e2a95471a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000998cd2182c160408000000000000000000000000000000000000000000000000410961c5b64ea2b40000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002c0a1f2ff0918a8ce280b32fe0a788c383f09f95b43e2a263a74f09d9e94327b3a501209d09c20bf9293d9dbcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4adcdc2f56cec17000000000000000000000000000000000000000000000000502b4832492bffaf000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000750a352f60772fe1bdbd4725f0928096767b46f09fab98efbfbd26f090baad3fc3b8e19c8c6f3d3cda8b3a282668f096abacefbfbd2ac2a5123c360476a14156004fe18479838663ab50fb8064b22e9c42d95c43a0e05c9eeb48b7c0cab8c49a6d4cc3693ac13a9c9c573511ed92e1403a2107393e7a00000000000000000000000000000000000000000000000000000000000000000000000000000000000041c071197b1b3e0e587dbb5a44b7fff5688c22d625ea39348a0c7985fd7564ab67b7e4cd01549cf54130c0db9a8f6464a79094975acded502cb7ee46111dfeedaa6600000000000000000000000000000000000000000000000000000000000000"}, {"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000020c8453e991df76b33e522ae6342bb3eb597820e000000000000000000000000000000000000000000000000000000000000046000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000000200001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d36cee1f8b6df20ebbe3acbbb15c2ac8c95f08d648e9c6c94fd66d541f928ec0000000000000000000000000000000000000000000000000f09719f3a61e6a000000000000000000000000000000000000000000000000023160cbfd105ee3e20be4e1a7c393e1bfbc9e8c6074844bbdb4d651e2dbc40203a6793910d9383d400000000000000000000000000000000000000000000000a6111b343da8607760000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000001e0f314316a3ad7080000000000000006869e9df8bbe2b20b00000000000000015f0b2c6d98cea80700000000000000023f0d686a4f45eebc000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000005a5d239ba4ac86e300000000000000000000000000000000000000000000000000e8074b1a9c256f000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000720a3c2ff09eb2ad27e18b855c7d4e20eaacb9262fe0a9873ce2b4a3f0918cb53ce0ae99f096aa87222ce0a6b2efbfbd5c642ef09f95b4f09f95b4f09f95b41232e2389cf6253053c93b94c3a71bb5d424cdab147a442b67282fb112a859c400570c33ee8a9112c15f8c906b13e7ade91b6bc900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d6a0c5a760ed3ceb5d816005628964f05c95b56b863654023d1000de5bfa16c7ae96f34b357603598886ce40838c825091f5aaff2bdd5345e5b42191df7780894a00000000000000000000000000000000000000000000000000000000000000"}, } + +var testMisbehaviourMessageABICases = []struct { + input string +}{ + // empty + {"00000000000000000000000000000000000000000000000000000000000000200001000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000011e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000010a00000000000000000000000000000000000000000000000000000000000001140000000000000000000000000000000000000000000000000000000000000002b00000000000000000000000000000000000000000000000050bcf546c2e98967000000000000000000000000000000000000000000000000a3f0ff88702fea963a609ac0979e0e70f3ab635ab1123a1140ee4d5b3bcf3596f1fc3076875367af0000000000000000000000000000000000000000000000002bd120851cc312fd0000000000000000000000000000000000000000000000006b0d969375bdeeecd88ef6da1f5da3a021d4741d6f7ef04859dec4a98b1c6dd9eccf3548eba3f150000000000000000000000000000000000000000000000000604af7d726d99a050000000000000000000000000000000000000000000000007c062945716f0b6615f4930d3e10ab7f7831abb3ca641158f88a65de7aaadc5912ce0fcc7c8a18900000000000000000000000000000000000000000000000000b37a89efd86b35e0000000000000000000000000000000000000000000000001345116edbf453adc533d39bf6a7c035936e5d4aa4cf38f83a2ab30951b4dec4e1870fee9ba181af000000000000000000000000000000000000000000000000b152b6eb99bcadc0000000000000000000000000000000000000000000000000ec3eac9611aa4d68074b910a3e6a2fcd4517242a16a9b2dbe228143b90d7c61877ffd677476cb70b000000000000000000000000000000000000000000000000607dc5661f7b44210000000000000000000000000000000000000000000000000f02efd19a08cdfe229958fd18017d1f342305bd4b113e7eb465e1e785af1561179e04cd3f5c077c000000000000000000000000000000000000000000000000bc9cd2558f7929310000000000000000000000000000000000000000000000006c0b0ba1f4365eaa6bdd95d4bde43030b035513f9b372edbc37ea594aaa32a58c62e499eb2263ef500000000000000000000000000000000000000000000000031b418292f5914ec00000000000000000000000000000000000000000000000046bff7e6ebeff10bc36d02485bc56bc2b1dbcd15037958db2ebbf43201dcd7c7c9deb435c5cdb4d100000000000000000000000000000000000000000000000006eae82a92a61de9000000000000000000000000000000000000000000000000efe3e86c68659ca31144f4dd617f43a5dd85e7740306003805c62d1410d1f160c55fb21f1e47077c000000000000000000000000000000000000000000000000dfdae3d6b27458ac0000000000000000000000000000000000000000000000008e620b9f810366ee6593c697ab2fba3e3c8b410f97841ab2ddc25ab58b5d2803c27e560ee063813d00000000000000000000000000000000000000000000000081cb611caac35ccc00000000000000000000000000000000000000000000000076c2c9a0b335b5a313a6096f66c3d588d3e28fcce4195c8a3e316c2daf6dffdd55dd6707b957c5f8000000000000000000000000000000000000000000000000577383713b2420c7000000000000000000000000000000000000000000000000fa4871d14b5bc9e116d9917dcc4424f8b45c4dcc9d087bdd1f4e989de29ed00a11b14606a453ad57000000000000000000000000000000000000000000000000b3c78442e91d6a19000000000000000000000000000000000000000000000000ceff4db90631a722f95f6967f88ec927101e647138183eece2e34280f0125334d448bf444f9ab934000000000000000000000000000000000000000000000000508bcc469accd6bf000000000000000000000000000000000000000000000000a22e3e929c8cad8c9560452e9d4c6ad0209e450b7ce17747953e2f0dd91bd5271644f50bd96d61c20000000000000000000000000000000000000000000000007e292bfaf20d1ae300000000000000000000000000000000000000000000000042fe9ea2408c44d5b51996393c23c76fea93e27dd8011d981fe78ce526cc8a80a0fcc47fc1e2ce23000000000000000000000000000000000000000000000000b051580b803ebdd3000000000000000000000000000000000000000000000000d95de84f6f92aed3e24525168d04c3e2a51233af84d9d3ec5feecf050292cdab262988dce521ccab0000000000000000000000000000000000000000000000004af9d46976fcd691000000000000000000000000000000000000000000000000227f78f496f46b8f7d6d826568b4abce29fca221d7d4bb7451b9cf0d5528dcfca012e64667f1e7020000000000000000000000000000000000000000000000005504c2cfe24ee1cd000000000000000000000000000000000000000000000000fb50b8404ae50ebf3d0bfb17cbe6f6346dd2a2e053208b35402fc1366facec1d67bdd002d89f2311000000000000000000000000000000000000000000000000ba0ee89dc4a860b5000000000000000000000000000000000000000000000000c4b8007414c9fe74f8554cbcc3ec2d558c32ca34231dc6c0d4c0a164604f478b0fce45d6a596dfa3000000000000000000000000000000000000000000000000126884fee490d0b7000000000000000000000000000000000000000000000000846b2a1c5747cab39c5c3478b71ce1ee330eced1d10975c3be6e6508a518e425d9359c05adf8c978000000000000000000000000000000000000000000000000a37a10287d96c362000000000000000000000000000000000000000000000000a158838acf85f6270d7f8e6209ba532a9ca3aa8bab08a6d95e6b2d97345cc6a93057690546b5e564000000000000000000000000000000000000000000000000303d06e7b48ebd87000000000000000000000000000000000000000000000000db5cdc630faccaa4e7242a6a554f12de27c06186a424c7e9417f8b6d7e0e4fb19c423825c83cd5a5000000000000000000000000000000000000000000000000f095ccefdc3e845700000000000000000000000000000000000000000000000021267c0e5779e6290dbd4fe0e29919b6e360096773dfaa98ae3b1daaebdfd9da0a5c868e60a49365000000000000000000000000000000000000000000000000f4162bd57084bf5c000000000000000000000000000000000000000000000000afcc9b9ec0b4d3f94ea61a7edb567068d59e2400f9f965a27fac2ea1213e493b80f5d20eb3a0fb3500000000000000000000000000000000000000000000000048c4756a72332fba0000000000000000000000000000000000000000000000004f9d511c3263f356947f7278fdf2c548d1421a9452e0068d220388de06c9c1e2bb72d90a0269d8b900000000000000000000000000000000000000000000000068c57ba7b90cb2e2000000000000000000000000000000000000000000000000a2335022458e0b4aa4bb071d42f16fa4ac92e135daab784c57a9320ddf8b98b942a3d867987ab45f00000000000000000000000000000000000000000000000050f3f6ddd9c1733e00000000000000000000000000000000000000000000000054d323815a69512ad32e78806566e00aaebf6a1a63f9d7aaec815bf855a326a508240a4062b62e84000000000000000000000000000000000000000000000000e69946648b5d57b40000000000000000000000000000000000000000000000005910cf2936576e0bfac8fe4f3d27e9a97e5f8fb34ce1aadc3216522a2b5c10f63083f2bb03ce0c7600000000000000000000000000000000000000000000000004e8d3c588ce9aff00000000000000000000000000000000000000000000000063b2b7107586b6eda94fa1a62d784f5ad46a8c572f98e44bd4f6cd566135b5cfcf6ceeb827a6cb1e00000000000000000000000000000000000000000000000063996ef644a1c96c0000000000000000000000000000000000000000000000008f0ff99ac23926c71a2ee46b9ff6efbca97de2c78e003f9e072fea27c38526a7b40d15a84b2cca8d000000000000000000000000000000000000000000000000a3825a441896f58f000000000000000000000000000000000000000000000000f9ac10a820334677cd1172ed6b9c717d262c96855cea773b89841fd5783fe490f3f5fc09a079e2070000000000000000000000000000000000000000000000006b71fcdcfbef642c0000000000000000000000000000000000000000000000008df274a37114343454e432adc4d8f7ea5d91dc5e87ab527c76e1e3704a4ed978e966cd84d56802a200000000000000000000000000000000000000000000000019fcefadfbca19df00000000000000000000000000000000000000000000000064d82f7fad2c6913874c4c8907184ee87cea285ecceb223aa305124e84d5209d2cd54eb04380deb5000000000000000000000000000000000000000000000000cb53bc2eb0d77146000000000000000000000000000000000000000000000000aeb0e1b071bfdfe5cf73859ccc7a8e9660d3ba1281d2ffd650747d9c5f2cb02069362f2d8e19f5e5000000000000000000000000000000000000000000000000a58b463c9a3077220000000000000000000000000000000000000000000000007720039a56e3e4c109f12be909296455140d00a46c03170c084e4a110cd3aae245058647021b13aa000000000000000000000000000000000000000000000000ec1aa1437ffe3acb000000000000000000000000000000000000000000000000be75cf57f8dbeea6a900c1f4760e2a4a77f26e7bdb1aa25df4f6ee84c7661becda05dcd7974e1503000000000000000000000000000000000000000000000000495f682b426c3c030000000000000000000000000000000000000000000000009c6391d17a930dbdf4d8aac486db4f03e55e099aee976cd6aa15e61eb21e633ff8ba42fdef5588ec000000000000000000000000000000000000000000000000b2caf7bf1d369ec60000000000000000000000000000000000000000000000006c9320c05b6d019ef9894c04e7d154e8220267efe5348b7acacea460e453bb570bd25fbdb2c156770000000000000000000000000000000000000000000000004807d695054529da000000000000000000000000000000000000000000000000d85d593800c0bea0afe13e6c8538ccb4c3eb1edea7d71f13e5f946c873b5704027283b203560a2a9000000000000000000000000000000000000000000000000f96e24679902deaa000000000000000000000000000000000000000000000000bcbb756c7683c4898205171aa19e1685d9ba87fd5906b08694db47a03736421604aa41e7d9d228230000000000000000000000000000000000000000000000000ed55f11ffcf191b0000000000000000000000000000000000000000000000005cd296e944e786d46e3e50efc7b22ef9257194350a81ec37d76c34fab1db1ffb668f66b3a7435b8d000000000000000000000000000000000000000000000000ce639b8ad3f682f10000000000000000000000000000000000000000000000006363ae33e4c5b08b434168d9e14eff3f9670cfac719b9dbfeae8c90c335be1e0fe9a01d70f8e33b5000000000000000000000000000000000000000000000000818af5c76a3b27e9000000000000000000000000000000000000000000000000d5ea70bfed18ccba2b513948f54f05e5c494b05c1f8d21bc3c7960f975e0a2264876d03f9857170c0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000490a2e26f09fa2acf0b28d907aefbfbdf0919297f09f95b43ff091a6b429c8ba2aed9fb5f09d92a55445f09d8487dbb35b12176277838a1d05c3506a30dc1b158785c3657360fb1f92cf0000000000000000000000000000000000000000000000"}, + {"00000000000000000000000000000000000000000000000000000000000000200001000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000005600000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000aebf4af22ffc0bd50000000000000000000000000000000000000000000000000c19c48201000f65f5e4e116e55deada3dab4557ba8667d53017408ce3744819edbcd611ec9f98d8000000000000000000000000000000000000000000000000dd57a1074100a38d000000000000000000000000000000000000000000000000e85875f76c35452f9bb5750e9494595d027d311b0fd9f6bdb8f224eec8c3593cf03f012da7e4f68000000000000000000000000000000000000000000000000068aab53205d57066000000000000000000000000000000000000000000000000e06a70940ffb40aceeb4e0df21468669c707f4ec2cf5b861b38cd47c4d0bbd46a6fda4bb9cb05ef10000000000000000000000000000000000000000000000006fbb13d76ffbd75c000000000000000000000000000000000000000000000000e8518dd53b3380da56a6b781a00a57141a8ed2b6b9f5297e5a26e8f103d05a835b3e8d6c85a7ade9000000000000000000000000000000000000000000000000e04f8c1fbf5addf800000000000000000000000000000000000000000000000070de490c2a092fc7987b7bc6014798b3bcab1165c142ecdbb337480a0842feab094ca5aa4a685b5300000000000000000000000000000000000000000000000071bb2efad0ac570d000000000000000000000000000000000000000000000000e8823fa0b13e9848f80e4d07d272d1dcf1ad5f9affa86299578deb5360c588ae0f16e5369238143e000000000000000000000000000000000000000000000000c9a953b7474936740000000000000000000000000000000000000000000000008e4db15f7ad1b59fe0d8b83e2997072048d5f6e9d32ccf4b2df516b643083d3cff6109052ab87c940000000000000000000000000000000000000000000000006935684209107cdc0000000000000000000000000000000000000000000000006303b58da0b7b672cbe18d43078c6f48a5d2748d99810d6e9ba872e32de1986423923b66a76552db0000000000000000000000000000000000000000000000006626666fd98c4be8000000000000000000000000000000000000000000000000ab7d218c5a6a76cfcd00789de244e64db515a8abad93292e4818fe9ab1c5346c968b99688c1db7a5000000000000000000000000000000000000000000000000b891ad652498cbf40000000000000000000000000000000000000000000000002d90221adc402b3e214d5d7cb6715322bb9c156db1cea742bb2c1c7a1638f463886107b58781dc6a000000000000000000000000000000000000000000000000e30dee1c8fe9e5e80000000000000000000000000000000000000000000000009f173b72ed18e1321505fe7380a27be8e630bb366a1ac4cb6bb7ad632bc7e7f8c983317a87ecb46800000000000000000000000000000000000000000000000032fd6955f95daf640000000000000000000000000000000000000000000000007a2a830a0413e9a458dd52d6dc244af81de312ee61f833fb38fa61ad19f96409826666bbfaa438bf00000000000000000000000000000000000000000000000088b8b15cdfd07ded000000000000000000000000000000000000000000000000be19c771e1ea6d69c419f0921097f7e303d8245302df69536c75164fe1e72710e21a8ecd2c95addc0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000480a214cefb8a0c3b0c39422f09383b64fe0afb645e386bd2a3cc2a5742e2f7e256058261223d7282d18330a7d3acc9f2e13b26bf822cf25e35d9f4948f0046854f7d032aa0f623617000000000000000000000000000000000000000000000000"}, + // trusting period + {"0000000000000000000000000000000000000000000000000000000000000020000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000e40000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000ce00000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000cedb5c3ddcc233f20000000000000000000000000000000000000000000000002bee197092b8129da32acc7b10f6fde9a85686da12d174f3d23e6a9d17fcc062b572319125ff4b720000000000000000000000000000000000000000000000009b7facebb0bef64e000000000000000000000000000000000000000000000000ab251177a80a42ba635066ac0d2e96a4b82719cd27a92c9da6f36363a94bdd804e0dfb1f378591d8000000000000000000000000000000000000000000000000d2031e1601071eb00000000000000000000000000000000000000000000000009be5e22308ca8fd0fe830f71b85695dbc506a3a1c78c9d18bb26a28bbd9c3d41b6d460e0fe3c3de90000000000000000000000000000000000000000000000000ee0d998302d904a00000000000000000000000000000000000000000000000015226757eef3ab52fb71c3f8c80d4f15288c0f6274e6c795d8b9c7476ea3877546dd940cee7d1d1b000000000000000000000000000000000000000000000000645c0644f57d74e30000000000000000000000000000000000000000000000001b71f46181ee485829b33f530c90beb75abef07ea244bb2402e252a84d782953ccf4d9b12a45293900000000000000000000000000000000000000000000000083eed5e30c8a9c50000000000000000000000000000000000000000000000000369592149593c2d5f4b296cdf7cdb332cd6d1a2d4785f79c6426d5d9d471e3c31c592173a2f8a1a30000000000000000000000000000000000000000000000008e436cb25ef72e34000000000000000000000000000000000000000000000000f22084692ea717e6b7c5875c8b82779c1a6f3b474bcd093a71f535de5cecd9c921a378635198f8120000000000000000000000000000000000000000000000008856b8f8fd4b731e000000000000000000000000000000000000000000000000b43dd097b815eade6d349a46ca492c268b7db6ac7453a3b72e5c4321555f2f3e164f5208a9eb4a97000000000000000000000000000000000000000000000000412b3b00cca0b6e9000000000000000000000000000000000000000000000000e981ecac829073410e1972290c95c42323097e82552faa0b2602c281b851126832ec768da455c0ba0000000000000000000000000000000000000000000000007c81956effa8bf7b000000000000000000000000000000000000000000000000749bca4015f9dc6f0ebdc802c55564de6a441f2fa2e3b5e7bc49922b02183319cae66e29cd27547d00000000000000000000000000000000000000000000000095cf3d93d7fad6e3000000000000000000000000000000000000000000000000f46afb617b24ef4099ca461fe2417731efce8e314a9f987436d2313c012c96f19828b7a8cfa83dad0000000000000000000000000000000000000000000000000a2a1bd9859d3b7c000000000000000000000000000000000000000000000000ec0a6f2038d325436194e860494b7584f0f860f37d13c4c194dec2d3e4ff23dd6609371e978eadf5000000000000000000000000000000000000000000000000e222b1d58f6d1f1a000000000000000000000000000000000000000000000000ae14d5e0839d2a6fa13aa1e061a910863e9fdbeb7ab212094180965079a7665bd7eebad2df4eeb5400000000000000000000000000000000000000000000000082b3bc7055a9c155000000000000000000000000000000000000000000000000243717aa24f429e20c02b0f98e21f8d5c8fdb8ad1cb0bce4e9a6604d3b1c7db52c84ea689b153a7a000000000000000000000000000000000000000000000000cfce710fba2ecc9b000000000000000000000000000000000000000000000000f4c1f4f6305edfbf3e83dff293dd67a2ca921a4ddd2a2487746a7092c97be15dbdabda1d2de6b5d900000000000000000000000000000000000000000000000061a4020e662e408c000000000000000000000000000000000000000000000000b719935656cd427aa18dc19f1c09e2f4cc3164ed607d8ed79fc89fe96707009993b6bf9ff082e86f000000000000000000000000000000000000000000000000787fb82a80b01c070000000000000000000000000000000000000000000000007454a6509c845900d5ed04ad2d04fb839052ccd1b24d7f1bc4a2b721eb6a1831f5f7c550b3a6ad49000000000000000000000000000000000000000000000000d2c1b3c117410df8000000000000000000000000000000000000000000000000528b19e2ad5e88878dd169093fbfe30984ca074db0640a3409650269a750f1425549eba40223cf880000000000000000000000000000000000000000000000007b8bed5987b04c7f00000000000000000000000000000000000000000000000044679b0eb17021a88c4f7513ff839b5d08f691d44ba2896a7febf3eb2a71ed7e9f56ce85abfd1a20000000000000000000000000000000000000000000000000bd933f7295c93647000000000000000000000000000000000000000000000000c0302b213162f55d6da09e296a3ef7e149ea9324954467b9430a5eea309eb25aabb36a3e8f6b6a4c0000000000000000000000000000000000000000000000005a72f141b24bf559000000000000000000000000000000000000000000000000ee9f7d001bdcdd33b9f0f75088b25d0bae56fee2cf7a9bfc204b51f252228050409c929598da54420000000000000000000000000000000000000000000000004c7d4142a6e8417b0000000000000000000000000000000000000000000000002290b053d642c11bebc32cda60726529d7f95317e05493f6bddd2b1f810ec3ee40b4e3c5af14bb04000000000000000000000000000000000000000000000000d43c752f92ae8e1c0000000000000000000000000000000000000000000000006c1e56a399b765b44ec13158fcb040085c9b5dc659df4f624971207a265bf5e0f1c4702dbf9cce180000000000000000000000000000000000000000000000009568af5ac12f61b80000000000000000000000000000000000000000000000003678f0876a5fca019d433732d18227dbbe1e49f26308fd2b31655027685ceb1f324200c620e2a9460000000000000000000000000000000000000000000000007b25fe4957f21f02000000000000000000000000000000000000000000000000e4b8faa1762ada1602ac6317049fea70e73cac2edf24fcec5ef642084735177838da8720915594b900000000000000000000000000000000000000000000000060502156a5a03e460000000000000000000000000000000000000000000000004a0ea8dacb716a1caab52ff7002b1322964eb64b6b99b09aa89bae43e3da740fe00feb75e30ed34a000000000000000000000000000000000000000000000000799030fa5df08ca00000000000000000000000000000000000000000000000003f7c9d3e7bc25153ce9d1f91be82c7c7c941025eb0d7738f62d6bd56baff0dec858463144518a5800000000000000000000000000000000000000000000000000406003260c52498000000000000000000000000000000000000000000000000734e2b2770735c71bd76f59660dfe94314796a41e7678d7b5287ddf5fd448fc94491b7d08fb3bad100000000000000000000000000000000000000000000000014dc186921534e8d0000000000000000000000000000000000000000000000001a2f2b21e417681b6f566b0c2b0123363d84047ef8c7b38255d049e53f922b30d6e0f747349f8e5e000000000000000000000000000000000000000000000000c47111c24ec6ec9d00000000000000000000000000000000000000000000000038e831281e8e60e8de0382fd8355c3544e3048a9824daf196d09fd495b29714d499ab17beff66fdc000000000000000000000000000000000000000000000000828fdfa480080356000000000000000000000000000000000000000000000000c2439825109913e293d803da07fc6259bc412d7a43ec6a484e0f436159cb7d30e068550bc6cd3938000000000000000000000000000000000000000000000000129d7642342d12b20000000000000000000000000000000000000000000000005b31da39b113b3bce59bcdef679a10d0e8f90d577829076eb1a968cc605cdec4b44497f57251ffb60000000000000000000000000000000000000000000000009d2ea8f656dc334300000000000000000000000000000000000000000000000082971995b5b152e600b8590213a7fa7b48155e7343324f6ccc74f3f207fade1907ddd33db8965cf600000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000020000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000580d1f0dcb44cc5f800000000000000004b3b6165e72b850e000000000000000d941be0ae1eef2df200000000000000095b275a892c7c0d53000000000000000000000000000000000000000000000000000000000000002e0a2c3723f09d9586c2a3f09f95b4c2a5e18fbc276ef09b84b23c63252e2a2524c2a57befb7bff09199acf090a8b1000000000000000000000000000000000000"}, + {"0000000000000000000000000000000000000000000000000000000000000020000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000adc2adefab68186200000000000000000000000000000000000000000000000058183a2aac0d098c8b0e8add66442df8b69ac3ca6636d1a52156a933fc3fcc818038fc8694e0fec800000000000000000000000000000000000000000000000089a9e6c17204b6cc000000000000000000000000000000000000000000000000d55b9da4c907e41f362ccd546895f4ed621a842256eaf4992f953924b5518822f54fcf58c04947e100000000000000000000000000000000000000000000000092c2f37c0c60c2bb000000000000000000000000000000000000000000000000bc9966abf90524482661315a9c39e04e3367b56f57cefeb2e189d2d14ba167743d2958a1d5c10e6d000000000000000000000000000000000000000000000000c393ff5ba730c35f0000000000000000000000000000000000000000000000000fae58e9ccf8c1f8e5f3d2eb8ecdf0655582e4f98fb9c1f74e1a830abe6bf22e20eb893794a508f4000000000000000000000000000000000000000000000000ed51efd1d342f629000000000000000000000000000000000000000000000000e8dc8da81f3bd38fb87c0db8f1619d524e1d9e37966e473a246158523e201edf1159524efccb64f7000000000000000000000000000000000000000000000000cf67bc5919fb64bf0000000000000000000000000000000000000000000000000c08aa46da14a9009001c353197dc2bab6bf64a886462a1fcebf7435a90cff921f8cce086a4ba7980000000000000000000000000000000000000000000000009be1a64faeb3e5d2000000000000000000000000000000000000000000000000c75fe200680a528ff101ecd277f5c6d10e4f69ca1e4782303e326bb220bf6bc22c9752d079edc4b50000000000000000000000000000000000000000000000009c299fb34a790ba300000000000000000000000000000000000000000000000036ac4f9d85deceb076da1176c37672a8274a0dae113a32fa928fcba6d2f92489c8b718ed20d8f4b000000000000000000000000000000000000000000000000083d8a9c09f933bea000000000000000000000000000000000000000000000000ae9590477d2341320c098cc363546254de84ec1cc1bbeff4598cbb54ed26e871ee7304809771c767000000000000000000000000000000000000000000000000486dc6e236a2ede60000000000000000000000000000000000000000000000006efb0feca088167df40038fde566e42c68bcb9bdd2e52adbb8ad510ca5948e5f75f1a888173cb79e00000000000000000000000000000000000000000000000061e14f44a723307600000000000000000000000000000000000000000000000069692b7406c26ba8ccdec992f31333435e9df7812cc096ead370b2e550c70c51c681bcc22e12f9e30000000000000000000000000000000000000000000000007fc214ed6353ff71000000000000000000000000000000000000000000000000655ba66137aba94784085401a00ba4921b3a70fe92ea94535c7c035966a646c0da90c197889417ca000000000000000000000000000000000000000000000000f46a830c70905a52000000000000000000000000000000000000000000000000c4f16b75a6f4ebdae9178f915ea4874eed6389ff5096b032b98f6254a8cc804b9417d206c323d28e00000000000000000000000000000000000000000000000078316846ae1a9f1900000000000000000000000000000000000000000000000033b983e1f9b058f234be60d2ce5a8ba590d2bd97789f9f297c5306c1db4947236cd55bc9a78d58e400000000000000000000000000000000000000000000000027a5de27853de5b5000000000000000000000000000000000000000000000000bb60869e2a387e4f2d3231d7ca1f8f322c5ebcebb46ed1fb256e4eeef15919eed514cff1efddd404000000000000000000000000000000000000000000000000eba9bb79db294a06000000000000000000000000000000000000000000000000919c492d1e096c10de6e1305072c6dd9d8ce84b6cddd9cef7aced01fcef9c7bf5359cd9f7f540bd50000000000000000000000000000000000000000000000002c63009d7b60e5d7000000000000000000000000000000000000000000000000665977e6ba2e2652c28ac8cee1bd1f14c3d5863722cc159396f4a4d60a6f5939121667fb10c09ab5000000000000000000000000000000000000000000000000ee53f5d6e0b6ba400000000000000000000000000000000000000000000000008b655dd817ab33fba05ed88445d34e0fab15ffedf4ac1e7f5100ec80ba85651eed972e6d40451fac00000000000000000000000000000000000000000000000040053a3088f563e00000000000000000000000000000000000000000000000000c8fcddf582d1e59ca04a9478c1802e5fb08ee7b55ca1582ac38c2600e9db3655207e9c91ec270ac000000000000000000000000000000000000000000000000a13f56400ba815b800000000000000000000000000000000000000000000000096d4dfad563ceb79c5ecdbbc97afd8c5f8742bd86425789b08f8eb9c0c948b66f2bcffb9eb52afd8000000000000000000000000000000000000000000000000513a2a11c328d76600000000000000000000000000000000000000000000000045e9c3c484c49a0803e286cc71dfa1b6911963c21b949797f9f4f52da4567c8b515f2121be8359dc000000000000000000000000000000000000000000000000b1c1ec07f35f0c8400000000000000000000000000000000000000000000000038601352a467c122f29882f05285557e1569266422f5864c8a7cc196a046fb6ca9cf050c9be808300000000000000000000000000000000000000000000000006d9336fefed8560c000000000000000000000000000000000000000000000000be4c5eba7566518e2bf30db909a77ccfa613a6a774398299e0e4e60a67fe194584713f814a61fdcc000000000000000000000000000000000000000000000000fa75273e6e057b0e0000000000000000000000000000000000000000000000000dd52bb483a8f2c35e05f61be8850d3b235c088f775e4fd5514ce7db1d3afbc636c0bae26e9974eb00000000000000000000000000000000000000000000000067f77c39120bbc81000000000000000000000000000000000000000000000000d1ed37b04dad4d84c6555739528237fc6410699abeaeb95fbcc5fb6c2fc6c891e25b08150755e315000000000000000000000000000000000000000000000000ba09062e91a8e6630000000000000000000000000000000000000000000000006deb6103d2baaecd16a73b75f442a321f74e21978ec057d24c4033d3f3971c8115f35e5ced04efb800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000200001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000006bf0ec65a355b113800000000000000066c1656f5e6cf41e20000000000000006883e824dd01c4ffe000000000000000b7e880340edcfaaf400000000000000000000000000000000000000000000000000000000000000540a45f09d92bbf09f809e226a7d6445455cf09f95b4d1a8c2a42273e1aaadf09095b353f090b2ade2b6b868f09f95b4f09da3b345f09b81ace0b08ac393f091a492f09eb987722f120b158df3f4244fe7cc5d538e000000000000000000000000"}, +} diff --git a/light-clients/lcp/types/misbehaviour_handle.go b/light-clients/lcp/types/misbehaviour_handle.go new file mode 100644 index 0000000..544e82c --- /dev/null +++ b/light-clients/lcp/types/misbehaviour_handle.go @@ -0,0 +1,56 @@ +package types + +import ( + "bytes" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/ethereum/go-ethereum/common" +) + +func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) bool { + switch msg := msg.(type) { + case *UpdateClientMessage: + m, err := msg.GetProxyMessage() + if err != nil { + return false + } + switch m.(type) { + case *MisbehaviourProxyMessage: + return true + default: + return false + } + default: + return false + } +} + +func (cs ClientState) verifyMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg *UpdateClientMessage, pmsg *MisbehaviourProxyMessage) error { + for _, state := range pmsg.PrevStates { + cons, err := GetConsensusState(clientStore, cdc, state.Height) + if err != nil { + return err + } + if !bytes.Equal(cons.StateId, state.StateID[:]) { + return sdkerrors.Wrapf(ErrInvalidMisbehaviour, "unexpected StateID: expected=%v actual=%v", cons.StateId, state.StateID) + } + } + + signer := common.BytesToAddress(msg.Signer) + if !cs.IsActiveKey(ctx.BlockTime(), clientStore, signer) { + return sdkerrors.Wrapf(ErrInvalidMisbehaviour, "signer '%v' not found", signer) + } + + if err := VerifySignatureWithSignBytes(msg.ProxyMessage, msg.Signature, signer); err != nil { + return sdkerrors.Wrapf(ErrInvalidMisbehaviour, err.Error()) + } + + if err := pmsg.Context.Validate(ctx.BlockTime()); err != nil { + return sdkerrors.Wrapf(ErrInvalidMisbehaviour, "invalid context: %v", err) + } + + return nil +} diff --git a/light-clients/lcp/types/update.go b/light-clients/lcp/types/update.go index b4378be..ba824dd 100644 --- a/light-clients/lcp/types/update.go +++ b/light-clients/lcp/types/update.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/datachainlab/lcp-go/sgx/ias" mapset "github.com/deckarep/golang-set/v2" @@ -17,7 +18,18 @@ import ( func (cs ClientState) VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) error { switch clientMsg := clientMsg.(type) { case *UpdateClientMessage: - return cs.verifyUpdateClient(ctx, cdc, clientStore, clientMsg) + pmsg, err := clientMsg.GetProxyMessage() + if err != nil { + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message: %v", err) + } + switch pmsg := pmsg.(type) { + case *UpdateStateProxyMessage: + return cs.verifyUpdateClient(ctx, cdc, clientStore, clientMsg, pmsg) + case *MisbehaviourProxyMessage: + return cs.verifyMisbehaviour(ctx, cdc, clientStore, clientMsg, pmsg) + default: + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "unexpected message type: %T", pmsg) + } case *RegisterEnclaveKeyMessage: return cs.verifyRegisterEnclaveKey(ctx, cdc, clientStore, clientMsg) default: @@ -25,39 +37,39 @@ func (cs ClientState) VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec } } -func (cs ClientState) verifyUpdateClient(ctx sdk.Context, cdc codec.BinaryCodec, store sdk.KVStore, message *UpdateClientMessage) error { - emsg, err := message.GetELCMessage() - if err != nil { - return err - } +func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg exported.ClientMessage) { + cs.Frozen = true + clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(cdc, &cs)) +} +func (cs ClientState) verifyUpdateClient(ctx sdk.Context, cdc codec.BinaryCodec, store sdk.KVStore, msg *UpdateClientMessage, pmsg *UpdateStateProxyMessage) error { if cs.LatestHeight.IsZero() { - if len(emsg.EmittedStates) == 0 { - return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message %v: `NewState` must be non-nil", message) + if len(pmsg.EmittedStates) == 0 { + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message %v: `NewState` must be non-nil", msg) } } else { - if emsg.PrevHeight == nil || emsg.PrevStateID == nil { - return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message %v: `PrevHeight` and `PrevStateID` must be non-nil", message) + if pmsg.PrevHeight == nil || pmsg.PrevStateID == nil { + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message %v: `PrevHeight` and `PrevStateID` must be non-nil", msg) } - prevConsensusState, err := GetConsensusState(store, cdc, emsg.PrevHeight) + prevConsensusState, err := GetConsensusState(store, cdc, pmsg.PrevHeight) if err != nil { return err } - if !bytes.Equal(prevConsensusState.StateId, emsg.PrevStateID[:]) { - return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "unexpected StateID: expected=%v actual=%v", prevConsensusState.StateId, emsg.PrevStateID[:]) + if !bytes.Equal(prevConsensusState.StateId, pmsg.PrevStateID[:]) { + return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "unexpected StateID: expected=%v actual=%v", prevConsensusState.StateId, pmsg.PrevStateID[:]) } } - signer := common.BytesToAddress(message.Signer) + signer := common.BytesToAddress(msg.Signer) if !cs.IsActiveKey(ctx.BlockTime(), store, signer) { return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "signer '%v' not found", signer) } - if err := VerifySignatureWithSignBytes(message.ElcMessage, message.Signature, signer); err != nil { + if err := VerifySignatureWithSignBytes(msg.ProxyMessage, msg.Signature, signer); err != nil { return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, err.Error()) } - if err := emsg.Context.Validate(ctx.BlockTime()); err != nil { + if err := pmsg.Context.Validate(ctx.BlockTime()); err != nil { return sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid context: %v", err) } @@ -110,7 +122,16 @@ func (cs ClientState) verifyRegisterEnclaveKey(ctx sdk.Context, cdc codec.Binary func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { switch clientMsg := clientMsg.(type) { case *UpdateClientMessage: - return cs.updateClient(ctx, cdc, clientStore, clientMsg) + pmsg, err := clientMsg.GetProxyMessage() + if err != nil { + panic(sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "invalid message: %v", err)) + } + switch pmsg := pmsg.(type) { + case *UpdateStateProxyMessage: + return cs.updateClient(ctx, cdc, clientStore, pmsg) + default: + panic(sdkerrors.Wrapf(clienttypes.ErrInvalidHeader, "unexpected message type: %T", pmsg)) + } case *RegisterEnclaveKeyMessage: return cs.registerEnclaveKey(ctx, cdc, clientStore, clientMsg) default: @@ -118,18 +139,14 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client } } -func (cs ClientState) updateClient(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, message *UpdateClientMessage) []exported.Height { - emsg, err := message.GetELCMessage() - if err != nil { - panic(err) - } - if cs.LatestHeight.LT(emsg.PostHeight) { - cs.LatestHeight = emsg.PostHeight +func (cs ClientState) updateClient(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, msg *UpdateStateProxyMessage) []exported.Height { + if cs.LatestHeight.LT(msg.PostHeight) { + cs.LatestHeight = msg.PostHeight } - consensusState := ConsensusState{StateId: emsg.PostStateID[:], Timestamp: emsg.Timestamp.Uint64()} + consensusState := ConsensusState{StateId: msg.PostStateID[:], Timestamp: msg.Timestamp.Uint64()} setClientState(clientStore, cdc, &cs) - setConsensusState(clientStore, cdc, &consensusState, emsg.PostHeight) + setConsensusState(clientStore, cdc, &consensusState, msg.PostHeight) return nil } diff --git a/relay/lcp.go b/relay/lcp.go index 4e6b77a..aea537a 100644 --- a/relay/lcp.go +++ b/relay/lcp.go @@ -366,9 +366,9 @@ func activateClient(pathEnd *core.PathEnd, src, dst *core.ProvableChain) error { var msgs []sdk.Msg for _, update := range updates { message := &lcptypes.UpdateClientMessage{ - ElcMessage: update.Message, - Signer: update.Signer, - Signature: update.Signature, + ProxyMessage: update.Message, + Signer: update.Signer, + Signature: update.Signature, } if err := message.ValidateBasic(); err != nil { return err diff --git a/relay/prover.go b/relay/prover.go index 611f32e..5b51f33 100644 --- a/relay/prover.go +++ b/relay/prover.go @@ -182,7 +182,7 @@ func (pr *Prover) SetupHeadersForUpdate(dstChain core.FinalityAwareChain, latest return nil, err } // ensure the message is valid - if _, err := lcptypes.EthABIDecodeHeaderedMessage(res.Message); err != nil { + if _, err := lcptypes.EthABIDecodeHeaderedProxyMessage(res.Message); err != nil { return nil, err } messages = append(messages, res.Message) @@ -202,9 +202,9 @@ func (pr *Prover) SetupHeadersForUpdate(dstChain core.FinalityAwareChain, latest log.GetLogger().Info("updateClient", "num_messages", len(messages)) for i := 0; i < len(messages); i++ { updates = append(updates, &lcptypes.UpdateClientMessage{ - ElcMessage: messages[i], - Signer: pr.activeEnclaveKey.EnclaveKeyAddress, - Signature: signatures[i], + ProxyMessage: messages[i], + Signer: pr.activeEnclaveKey.EnclaveKeyAddress, + Signature: signatures[i], }) } } @@ -227,9 +227,9 @@ func (pr *Prover) aggregateMessages(messages [][]byte, signatures [][]byte, sign return nil, fmt.Errorf("unexpected error: messages must not be empty") } else if mn == 1 { return &lcptypes.UpdateClientMessage{ - ElcMessage: batches[0].Messages[0], - Signer: batches[0].Signer, - Signature: batches[0].Signatures[0], + ProxyMessage: batches[0].Messages[0], + Signer: batches[0].Signer, + Signature: batches[0].Signatures[0], }, nil } else { resp, err := pr.lcpServiceClient.AggregateMessages(context.TODO(), &elc.MsgAggregateMessages{ @@ -241,9 +241,9 @@ func (pr *Prover) aggregateMessages(messages [][]byte, signatures [][]byte, sign return nil, err } return &lcptypes.UpdateClientMessage{ - ElcMessage: resp.Message, - Signer: resp.Signer, - Signature: resp.Signature, + ProxyMessage: resp.Message, + Signer: resp.Signer, + Signature: resp.Signature, }, nil } } else if n == 0 { @@ -318,11 +318,11 @@ func (pr *Prover) ProveState(ctx core.QueryContext, path string, value []byte) ( if err != nil { return nil, clienttypes.Height{}, err } - message, err := lcptypes.EthABIDecodeHeaderedMessage(res.Message) + message, err := lcptypes.EthABIDecodeHeaderedProxyMessage(res.Message) if err != nil { return nil, clienttypes.Height{}, err } - sc, err := message.GetVerifyMembershipMessage() + sc, err := message.GetVerifyMembershipProxyMessage() if err != nil { return nil, clienttypes.Height{}, err } diff --git a/relay/restore.go b/relay/restore.go index 8dccaa7..091cb88 100644 --- a/relay/restore.go +++ b/relay/restore.go @@ -103,19 +103,19 @@ func (pr *Prover) restoreELCState(ctx context.Context, counterparty core.Finalit // Ensure the restored state is correct - commitment, err := lcptypes.EthABIDecodeHeaderedMessage(res.Message) + commitment, err := lcptypes.EthABIDecodeHeaderedProxyMessage(res.Message) if err != nil { return err } - ucm, err := commitment.GetUpdateClientMessage() + usm, err := commitment.GetUpdateStateProxyMessage() if err != nil { return err } - if !ucm.PostStateID.EqualBytes(consensusState.StateId) { - return fmt.Errorf("unexpected state id: expected %v, but got %v", ucm.PostStateID, consensusState.StateId) + if !usm.PostStateID.EqualBytes(consensusState.StateId) { + return fmt.Errorf("unexpected state id: expected %v, but got %v", usm.PostStateID, consensusState.StateId) } - if !ucm.PostHeight.EQ(restoreHeight) { - return fmt.Errorf("unexpected height: expected %v, but got %v", restoreHeight, ucm.PostHeight) + if !usm.PostHeight.EQ(restoreHeight) { + return fmt.Errorf("unexpected height: expected %v, but got %v", restoreHeight, usm.PostHeight) } // TODO relayer should update res.ClientId in the config @@ -123,7 +123,7 @@ func (pr *Prover) restoreELCState(ctx context.Context, counterparty core.Finalit return fmt.Errorf("you must specify '%v' as elc_client_id, but got %v", res.ClientId, pr.config.ElcClientId) } - log.Printf("successfully restored ELC state: client_id=%v, state_id=%v, height=%v", res.ClientId, ucm.PostStateID, ucm.PostHeight) + log.Printf("successfully restored ELC state: client_id=%v, state_id=%v, height=%v", res.ClientId, usm.PostStateID, usm.PostHeight) return nil }