diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index 3a9b0f8c6e..06c3622e3a 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -1,600 +1,600 @@ package ibc -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "net/url" - "strconv" - "strings" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/go-wire" - merkle "github.com/tendermint/merkleeyes/iavl" - cmn "github.com/tendermint/tmlibs/common" - - "github.com/tendermint/basecoin/types" - tm "github.com/tendermint/tendermint/types" -) - -const ( - // Key parts - _IBC = "ibc" - _BLOCKCHAIN = "blockchain" - _GENESIS = "genesis" - _STATE = "state" - _HEADER = "header" - _EGRESS = "egress" - _INGRESS = "ingress" - _CONNECTION = "connection" -) - -type IBCPluginState struct { - // @[:ibc, :blockchain, :genesis, ChainID] <~ BlockchainGenesis - // @[:ibc, :blockchain, :state, ChainID] <~ BlockchainState - // @[:ibc, :blockchain, :header, ChainID, Height] <~ tm.Header - // @[:ibc, :egress, Src, Dst, Sequence] <~ Packet - // @[:ibc, :ingress, Dst, Src, Sequence] <~ Packet - // @[:ibc, :connection, Src, Dst] <~ Connection # TODO - keep connection state -} - -type BlockchainGenesis struct { - ChainID string - Genesis string -} - -type BlockchainState struct { - ChainID string - Validators []*tm.Validator - LastBlockHash []byte - LastBlockHeight uint64 -} - -type Packet struct { - SrcChainID string - DstChainID string - Sequence uint64 - Type string // redundant now that Type() is a method on Payload ? - Payload Payload -} - -func NewPacket(src, dst string, seq uint64, payload Payload) Packet { - return Packet{ - SrcChainID: src, - DstChainID: dst, - Sequence: seq, - Type: payload.Type(), - Payload: payload, - } -} - -// GetSequenceNumber gets the sequence number for packets being sent from the src chain to the dst chain. -// The sequence number counts how many packets have been sent. -// The next packet must include the latest sequence number. -func GetSequenceNumber(store types.KVStore, src, dst string) uint64 { - sequenceKey := toKey(_IBC, _EGRESS, src, dst) - seqBytes := store.Get(sequenceKey) - if seqBytes == nil { - return 0 - } - seq, err := strconv.ParseUint(string(seqBytes), 10, 64) - if err != nil { - cmn.PanicSanity(err.Error()) - } - return seq -} - -// SetSequenceNumber sets the sequence number for packets being sent from the src chain to the dst chain -func SetSequenceNumber(store types.KVStore, src, dst string, seq uint64) { - sequenceKey := toKey(_IBC, _EGRESS, src, dst) - store.Set(sequenceKey, []byte(strconv.FormatUint(seq, 10))) -} - -// SaveNewIBCPacket creates an IBC packet with the given payload from the src chain to the dst chain -// using the correct sequence number. It also increments the sequence number by 1 -func SaveNewIBCPacket(state types.KVStore, src, dst string, payload Payload) { - // fetch sequence number and increment by 1 - seq := GetSequenceNumber(state, src, dst) - SetSequenceNumber(state, src, dst, seq+1) - - // save ibc packet - packetKey := toKey(_IBC, _EGRESS, src, dst, cmn.Fmt("%v", seq)) - packet := NewPacket(src, dst, uint64(seq), payload) - save(state, packetKey, packet) -} - -func GetIBCPacket(state types.KVStore, src, dst string, seq uint64) (Packet, error) { - packetKey := toKey(_IBC, _EGRESS, src, dst, cmn.Fmt("%v", seq)) - packetBytes := state.Get(packetKey) - - var packet Packet - err := wire.ReadBinaryBytes(packetBytes, &packet) - return packet, err -} - -//-------------------------------------------------------------------------------- - -const ( - PayloadTypeBytes = byte(0x01) - PayloadTypeCoins = byte(0x02) -) - -var _ = wire.RegisterInterface( - struct{ Payload }{}, - wire.ConcreteType{DataPayload{}, PayloadTypeBytes}, - wire.ConcreteType{CoinsPayload{}, PayloadTypeCoins}, -) - -type Payload interface { - AssertIsPayload() - Type() string - ValidateBasic() abci.Result -} - -func (DataPayload) AssertIsPayload() {} -func (CoinsPayload) AssertIsPayload() {} - -type DataPayload []byte - -func (p DataPayload) Type() string { - return "data" -} - -func (p DataPayload) ValidateBasic() abci.Result { - return abci.OK -} - -type CoinsPayload struct { - Address []byte - Coins types.Coins -} - -func (p CoinsPayload) Type() string { - return "coin" -} - -func (p CoinsPayload) ValidateBasic() abci.Result { - // TODO: validate - return abci.OK -} - -//-------------------------------------------------------------------------------- - -const ( - IBCTxTypeRegisterChain = byte(0x01) - IBCTxTypeUpdateChain = byte(0x02) - IBCTxTypePacketCreate = byte(0x03) - IBCTxTypePacketPost = byte(0x04) - - IBCCodeEncodingError = abci.CodeType(1001) - IBCCodeChainAlreadyExists = abci.CodeType(1002) - IBCCodePacketAlreadyExists = abci.CodeType(1003) - IBCCodeUnknownHeight = abci.CodeType(1004) - IBCCodeInvalidCommit = abci.CodeType(1005) - IBCCodeInvalidProof = abci.CodeType(1006) -) - -var _ = wire.RegisterInterface( - struct{ IBCTx }{}, - wire.ConcreteType{IBCRegisterChainTx{}, IBCTxTypeRegisterChain}, - wire.ConcreteType{IBCUpdateChainTx{}, IBCTxTypeUpdateChain}, - wire.ConcreteType{IBCPacketCreateTx{}, IBCTxTypePacketCreate}, - wire.ConcreteType{IBCPacketPostTx{}, IBCTxTypePacketPost}, -) - -type IBCTx interface { - AssertIsIBCTx() - ValidateBasic() abci.Result -} - -func (IBCRegisterChainTx) AssertIsIBCTx() {} -func (IBCUpdateChainTx) AssertIsIBCTx() {} -func (IBCPacketCreateTx) AssertIsIBCTx() {} -func (IBCPacketPostTx) AssertIsIBCTx() {} - -type IBCRegisterChainTx struct { - BlockchainGenesis -} - -func (IBCRegisterChainTx) ValidateBasic() (res abci.Result) { - // TODO - validate - return -} - -type IBCUpdateChainTx struct { - Header tm.Header - Commit tm.Commit - // TODO: NextValidators -} - -func (IBCUpdateChainTx) ValidateBasic() (res abci.Result) { - // TODO - validate - return -} - -type IBCPacketCreateTx struct { - Packet -} - -func (IBCPacketCreateTx) ValidateBasic() (res abci.Result) { - // TODO - validate - return -} - -type IBCPacketPostTx struct { - FromChainID string // The immediate source of the packet, not always Packet.SrcChainID - FromChainHeight uint64 // The block height in which Packet was committed, to check Proof - Packet - Proof *merkle.IAVLProof -} - -func (IBCPacketPostTx) ValidateBasic() (res abci.Result) { - // TODO - validate - return -} - -//-------------------------------------------------------------------------------- - -type IBCPlugin struct { -} - -func (ibc *IBCPlugin) Name() string { - return "IBC" -} - -func (ibc *IBCPlugin) StateKey() []byte { - return []byte("IBCPlugin.State") -} - -func New() *IBCPlugin { - return &IBCPlugin{} -} - -func (ibc *IBCPlugin) SetOption(store types.KVStore, key string, value string) (log string) { - return "" -} - -func (ibc *IBCPlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { - // Decode tx - var tx IBCTx - err := wire.ReadBinaryBytes(txBytes, &tx) - if err != nil { - return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) - } - - // Validate tx - res = tx.ValidateBasic() - if res.IsErr() { - return res.PrependLog("ValidateBasic Failed: ") - } - - // TODO - Check whether sufficient funds - - defer func() { - // TODO - Refund any remaining funds left over - // e.g. !ctx.Coins.Minus(tx.Fee).IsZero() - // ctx.CallerAccount is synced w/ store, so just modify that and store it. - // NOTE: We should use the CallContext to store fund/refund information. - }() - - sm := &IBCStateMachine{store, ctx, abci.OK} - - switch tx := tx.(type) { - case IBCRegisterChainTx: - sm.runRegisterChainTx(tx) - case IBCUpdateChainTx: - sm.runUpdateChainTx(tx) - case IBCPacketCreateTx: - sm.runPacketCreateTx(tx) - case IBCPacketPostTx: - sm.runPacketPostTx(tx) - } - - return sm.res -} - -type IBCStateMachine struct { - store types.KVStore - ctx types.CallContext - res abci.Result -} - -func (sm *IBCStateMachine) runRegisterChainTx(tx IBCRegisterChainTx) { - chainGenKey := toKey(_IBC, _BLOCKCHAIN, _GENESIS, tx.ChainID) - chainStateKey := toKey(_IBC, _BLOCKCHAIN, _STATE, tx.ChainID) - chainGen := tx.BlockchainGenesis - - // Parse genesis - chainGenDoc := new(tm.GenesisDoc) - err := json.Unmarshal([]byte(chainGen.Genesis), chainGenDoc) - if err != nil { - sm.res.Code = IBCCodeEncodingError - sm.res.Log = "Genesis doc couldn't be parsed: " + err.Error() - return - } - - // Make sure chainGen doesn't already exist - if exists(sm.store, chainGenKey) { - sm.res.Code = IBCCodeChainAlreadyExists - sm.res.Log = "Already exists" - return - } - - // Save new BlockchainGenesis - save(sm.store, chainGenKey, chainGen) - - // Create new BlockchainState - chainState := BlockchainState{ - ChainID: chainGenDoc.ChainID, - Validators: make([]*tm.Validator, len(chainGenDoc.Validators)), - LastBlockHash: nil, - LastBlockHeight: 0, - } - // Make validators slice - for i, val := range chainGenDoc.Validators { - pubKey := val.PubKey - address := pubKey.Address() - chainState.Validators[i] = &tm.Validator{ - Address: address, - PubKey: pubKey, - VotingPower: val.Amount, - } - } - - // Save new BlockchainState - save(sm.store, chainStateKey, chainState) -} - -func (sm *IBCStateMachine) runUpdateChainTx(tx IBCUpdateChainTx) { - chainID := tx.Header.ChainID - chainStateKey := toKey(_IBC, _BLOCKCHAIN, _STATE, chainID) - - // Make sure chainState exists - if !exists(sm.store, chainStateKey) { - return // Chain does not exist, do nothing - } - - // Load latest chainState - var chainState BlockchainState - exists, err := load(sm.store, chainStateKey, &chainState) - if err != nil { - sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Loading ChainState: %v", err.Error())) - return - } - if !exists { - sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Missing ChainState")) - return - } - - // Check commit against last known state & validators - err = verifyCommit(chainState, &tx.Header, &tx.Commit) - if err != nil { - sm.res.Code = IBCCodeInvalidCommit - sm.res.Log = cmn.Fmt("Invalid Commit: %v", err.Error()) - return - } - - // Store header - headerKey := toKey(_IBC, _BLOCKCHAIN, _HEADER, chainID, cmn.Fmt("%v", tx.Header.Height)) - save(sm.store, headerKey, tx.Header) - - // Update chainState - chainState.LastBlockHash = tx.Header.Hash() - chainState.LastBlockHeight = uint64(tx.Header.Height) - - // Store chainState - save(sm.store, chainStateKey, chainState) -} - -func (sm *IBCStateMachine) runPacketCreateTx(tx IBCPacketCreateTx) { - packet := tx.Packet - packetKey := toKey(_IBC, _EGRESS, - packet.SrcChainID, - packet.DstChainID, - cmn.Fmt("%v", packet.Sequence), - ) - // Make sure packet doesn't already exist - if exists(sm.store, packetKey) { - sm.res.Code = IBCCodePacketAlreadyExists - // TODO: .AppendLog() does not update sm.res - sm.res.Log = "Already exists" - return - } - - // Execute the payload - switch payload := tx.Packet.Payload.(type) { - case DataPayload: - // do nothing - case CoinsPayload: - // ensure enough coins were sent in tx to cover the payload coins - if !sm.ctx.Coins.IsGTE(payload.Coins) { - sm.res.Code = abci.CodeType_InsufficientFunds - sm.res.Log = fmt.Sprintf("Not enough funds sent in tx (%v) to send %v via IBC", sm.ctx.Coins, payload.Coins) - return - } - - // deduct coins from context - sm.ctx.Coins = sm.ctx.Coins.Minus(payload.Coins) - } - - // Save new Packet - save(sm.store, packetKey, packet) - - // set the sequence number - SetSequenceNumber(sm.store, packet.SrcChainID, packet.DstChainID, packet.Sequence) -} - -func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { - packet := tx.Packet - packetKeyEgress := toKey(_IBC, _EGRESS, - packet.SrcChainID, - packet.DstChainID, - cmn.Fmt("%v", packet.Sequence), - ) - packetKeyIngress := toKey(_IBC, _INGRESS, - packet.DstChainID, - packet.SrcChainID, - cmn.Fmt("%v", packet.Sequence), - ) - headerKey := toKey(_IBC, _BLOCKCHAIN, _HEADER, - tx.FromChainID, - cmn.Fmt("%v", tx.FromChainHeight), - ) - - // Make sure packet doesn't already exist - if exists(sm.store, packetKeyIngress) { - sm.res.Code = IBCCodePacketAlreadyExists - sm.res.Log = "Already exists" - return - } - - // Save new Packet (just for fun) - save(sm.store, packetKeyIngress, packet) - - // Load Header and make sure it exists - // If it exists, we already checked a valid commit for it in UpdateChainTx - var header tm.Header - exists, err := load(sm.store, headerKey, &header) - if err != nil { - sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Loading Header: %v", err.Error())) - return - } - if !exists { - sm.res.Code = IBCCodeUnknownHeight - sm.res.Log = cmn.Fmt("Loading Header: Unknown height") - return - } - - proof := tx.Proof - if proof == nil { - sm.res.Code = IBCCodeInvalidProof - sm.res.Log = "Proof is nil" - return - } - packetBytes := wire.BinaryBytes(packet) - - // Make sure packet's proof matches given (packet, key, blockhash) - ok := proof.Verify(packetKeyEgress, packetBytes, header.AppHash) - if !ok { - sm.res.Code = IBCCodeInvalidProof - sm.res.Log = fmt.Sprintf("Proof is invalid. key: %s; packetByes %X; header %v; proof %v", packetKeyEgress, packetBytes, header, proof) - return - } - - // Execute payload - switch payload := packet.Payload.(type) { - case DataPayload: - // do nothing - case CoinsPayload: - // Add coins to destination account - acc := types.GetAccount(sm.store, payload.Address) - if acc == nil { - acc = &types.Account{} - } - acc.Balance = acc.Balance.Plus(payload.Coins) - types.SetAccount(sm.store, payload.Address, acc) - } - - return -} - -func (ibc *IBCPlugin) InitChain(store types.KVStore, vals []*abci.Validator) { -} - -func (cp *IBCPlugin) BeginBlock(store types.KVStore, hash []byte, header *abci.Header) { -} - -func (cp *IBCPlugin) EndBlock(store types.KVStore, height uint64) (res abci.ResponseEndBlock) { - return -} - -//-------------------------------------------------------------------------------- -// TODO: move to utils - -// Returns true if exists, false if nil. -func exists(store types.KVStore, key []byte) (exists bool) { - value := store.Get(key) - return len(value) > 0 -} - -// Load bytes from store by reading value for key and read into ptr. -// Returns true if exists, false if nil. -// Returns err if decoding error. -func load(store types.KVStore, key []byte, ptr interface{}) (exists bool, err error) { - value := store.Get(key) - if len(value) > 0 { - err = wire.ReadBinaryBytes(value, ptr) - if err != nil { - return true, errors.New( - cmn.Fmt("Error decoding key 0x%X = 0x%X: %v", key, value, err.Error()), - ) - } - return true, nil - } else { - return false, nil - } -} - -// Save bytes to store by writing obj's go-wire binary bytes. -func save(store types.KVStore, key []byte, obj interface{}) { - store.Set(key, wire.BinaryBytes(obj)) -} - -// Key parts are URL escaped and joined with ',' -func toKey(parts ...string) []byte { - escParts := make([]string, len(parts)) - for i, part := range parts { - escParts[i] = url.QueryEscape(part) - } - return []byte(strings.Join(escParts, ",")) -} - -// NOTE: Commit's votes include ValidatorAddress, so can be matched up -// against chainState.Validators, even if the validator set had changed. -// For the purpose of the demo, we assume that the validator set hadn't changed, -// though we should check that explicitly. -func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Commit) error { - - // Ensure that chainState and header ChainID match. - if chainState.ChainID != header.ChainID { - return errors.New(cmn.Fmt("Expected header.ChainID %v, got %v", chainState.ChainID, header.ChainID)) - } - // Ensure things aren't empty - if len(chainState.Validators) == 0 { - return errors.New(cmn.Fmt("Blockchain has no validators")) // NOTE: Why would this happen? - } - if len(commit.Precommits) == 0 { - return errors.New(cmn.Fmt("Commit has no signatures")) - } - chainID := chainState.ChainID - vals := chainState.Validators - valSet := tm.NewValidatorSet(vals) - - var blockID tm.BlockID - for _, pc := range commit.Precommits { - // XXX: incorrect. we want the one for +2/3, not just the first one - if pc != nil { - blockID = pc.BlockID - } - } - if blockID.IsZero() { - return errors.New("All precommits are nil!") - } - - // NOTE: Currently this only works with the exact same validator set. - // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose - // the functionality to verify commits even after validator changes. - err := valSet.VerifyCommit(chainID, blockID, header.Height, commit) - if err != nil { - return err - } - - // Ensure the committed blockID matches the header - if !bytes.Equal(header.Hash(), blockID.Hash) { - return errors.New(cmn.Fmt("blockID.Hash (%X) does not match header.Hash (%X)", blockID.Hash, header.Hash())) - } - - // All ok! - return nil -} +// import ( +// "bytes" +// "encoding/json" +// "errors" +// "fmt" +// "net/url" +// "strconv" +// "strings" + +// abci "github.com/tendermint/abci/types" +// "github.com/tendermint/go-wire" +// merkle "github.com/tendermint/merkleeyes/iavl" +// cmn "github.com/tendermint/tmlibs/common" + +// "github.com/tendermint/basecoin/types" +// tm "github.com/tendermint/tendermint/types" +// ) + +// const ( +// // Key parts +// _IBC = "ibc" +// _BLOCKCHAIN = "blockchain" +// _GENESIS = "genesis" +// _STATE = "state" +// _HEADER = "header" +// _EGRESS = "egress" +// _INGRESS = "ingress" +// _CONNECTION = "connection" +// ) + +// type IBCPluginState struct { +// // @[:ibc, :blockchain, :genesis, ChainID] <~ BlockchainGenesis +// // @[:ibc, :blockchain, :state, ChainID] <~ BlockchainState +// // @[:ibc, :blockchain, :header, ChainID, Height] <~ tm.Header +// // @[:ibc, :egress, Src, Dst, Sequence] <~ Packet +// // @[:ibc, :ingress, Dst, Src, Sequence] <~ Packet +// // @[:ibc, :connection, Src, Dst] <~ Connection # TODO - keep connection state +// } + +// type BlockchainGenesis struct { +// ChainID string +// Genesis string +// } + +// type BlockchainState struct { +// ChainID string +// Validators []*tm.Validator +// LastBlockHash []byte +// LastBlockHeight uint64 +// } + +// type Packet struct { +// SrcChainID string +// DstChainID string +// Sequence uint64 +// Type string // redundant now that Type() is a method on Payload ? +// Payload Payload +// } + +// func NewPacket(src, dst string, seq uint64, payload Payload) Packet { +// return Packet{ +// SrcChainID: src, +// DstChainID: dst, +// Sequence: seq, +// Type: payload.Type(), +// Payload: payload, +// } +// } + +// // GetSequenceNumber gets the sequence number for packets being sent from the src chain to the dst chain. +// // The sequence number counts how many packets have been sent. +// // The next packet must include the latest sequence number. +// func GetSequenceNumber(store types.KVStore, src, dst string) uint64 { +// sequenceKey := toKey(_IBC, _EGRESS, src, dst) +// seqBytes := store.Get(sequenceKey) +// if seqBytes == nil { +// return 0 +// } +// seq, err := strconv.ParseUint(string(seqBytes), 10, 64) +// if err != nil { +// cmn.PanicSanity(err.Error()) +// } +// return seq +// } + +// // SetSequenceNumber sets the sequence number for packets being sent from the src chain to the dst chain +// func SetSequenceNumber(store types.KVStore, src, dst string, seq uint64) { +// sequenceKey := toKey(_IBC, _EGRESS, src, dst) +// store.Set(sequenceKey, []byte(strconv.FormatUint(seq, 10))) +// } + +// // SaveNewIBCPacket creates an IBC packet with the given payload from the src chain to the dst chain +// // using the correct sequence number. It also increments the sequence number by 1 +// func SaveNewIBCPacket(state types.KVStore, src, dst string, payload Payload) { +// // fetch sequence number and increment by 1 +// seq := GetSequenceNumber(state, src, dst) +// SetSequenceNumber(state, src, dst, seq+1) + +// // save ibc packet +// packetKey := toKey(_IBC, _EGRESS, src, dst, cmn.Fmt("%v", seq)) +// packet := NewPacket(src, dst, uint64(seq), payload) +// save(state, packetKey, packet) +// } + +// func GetIBCPacket(state types.KVStore, src, dst string, seq uint64) (Packet, error) { +// packetKey := toKey(_IBC, _EGRESS, src, dst, cmn.Fmt("%v", seq)) +// packetBytes := state.Get(packetKey) + +// var packet Packet +// err := wire.ReadBinaryBytes(packetBytes, &packet) +// return packet, err +// } + +// //-------------------------------------------------------------------------------- + +// const ( +// PayloadTypeBytes = byte(0x01) +// PayloadTypeCoins = byte(0x02) +// ) + +// var _ = wire.RegisterInterface( +// struct{ Payload }{}, +// wire.ConcreteType{DataPayload{}, PayloadTypeBytes}, +// wire.ConcreteType{CoinsPayload{}, PayloadTypeCoins}, +// ) + +// type Payload interface { +// AssertIsPayload() +// Type() string +// ValidateBasic() abci.Result +// } + +// func (DataPayload) AssertIsPayload() {} +// func (CoinsPayload) AssertIsPayload() {} + +// type DataPayload []byte + +// func (p DataPayload) Type() string { +// return "data" +// } + +// func (p DataPayload) ValidateBasic() abci.Result { +// return abci.OK +// } + +// type CoinsPayload struct { +// Address []byte +// Coins types.Coins +// } + +// func (p CoinsPayload) Type() string { +// return "coin" +// } + +// func (p CoinsPayload) ValidateBasic() abci.Result { +// // TODO: validate +// return abci.OK +// } + +// //-------------------------------------------------------------------------------- + +// const ( +// IBCTxTypeRegisterChain = byte(0x01) +// IBCTxTypeUpdateChain = byte(0x02) +// IBCTxTypePacketCreate = byte(0x03) +// IBCTxTypePacketPost = byte(0x04) + +// IBCCodeEncodingError = abci.CodeType(1001) +// IBCCodeChainAlreadyExists = abci.CodeType(1002) +// IBCCodePacketAlreadyExists = abci.CodeType(1003) +// IBCCodeUnknownHeight = abci.CodeType(1004) +// IBCCodeInvalidCommit = abci.CodeType(1005) +// IBCCodeInvalidProof = abci.CodeType(1006) +// ) + +// var _ = wire.RegisterInterface( +// struct{ IBCTx }{}, +// wire.ConcreteType{IBCRegisterChainTx{}, IBCTxTypeRegisterChain}, +// wire.ConcreteType{IBCUpdateChainTx{}, IBCTxTypeUpdateChain}, +// wire.ConcreteType{IBCPacketCreateTx{}, IBCTxTypePacketCreate}, +// wire.ConcreteType{IBCPacketPostTx{}, IBCTxTypePacketPost}, +// ) + +// type IBCTx interface { +// AssertIsIBCTx() +// ValidateBasic() abci.Result +// } + +// func (IBCRegisterChainTx) AssertIsIBCTx() {} +// func (IBCUpdateChainTx) AssertIsIBCTx() {} +// func (IBCPacketCreateTx) AssertIsIBCTx() {} +// func (IBCPacketPostTx) AssertIsIBCTx() {} + +// type IBCRegisterChainTx struct { +// BlockchainGenesis +// } + +// func (IBCRegisterChainTx) ValidateBasic() (res abci.Result) { +// // TODO - validate +// return +// } + +// type IBCUpdateChainTx struct { +// Header tm.Header +// Commit tm.Commit +// // TODO: NextValidators +// } + +// func (IBCUpdateChainTx) ValidateBasic() (res abci.Result) { +// // TODO - validate +// return +// } + +// type IBCPacketCreateTx struct { +// Packet +// } + +// func (IBCPacketCreateTx) ValidateBasic() (res abci.Result) { +// // TODO - validate +// return +// } + +// type IBCPacketPostTx struct { +// FromChainID string // The immediate source of the packet, not always Packet.SrcChainID +// FromChainHeight uint64 // The block height in which Packet was committed, to check Proof +// Packet +// Proof *merkle.IAVLProof +// } + +// func (IBCPacketPostTx) ValidateBasic() (res abci.Result) { +// // TODO - validate +// return +// } + +// //-------------------------------------------------------------------------------- + +// type IBCPlugin struct { +// } + +// func (ibc *IBCPlugin) Name() string { +// return "IBC" +// } + +// func (ibc *IBCPlugin) StateKey() []byte { +// return []byte("IBCPlugin.State") +// } + +// func New() *IBCPlugin { +// return &IBCPlugin{} +// } + +// func (ibc *IBCPlugin) SetOption(store types.KVStore, key string, value string) (log string) { +// return "" +// } + +// func (ibc *IBCPlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { +// // Decode tx +// var tx IBCTx +// err := wire.ReadBinaryBytes(txBytes, &tx) +// if err != nil { +// return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) +// } + +// // Validate tx +// res = tx.ValidateBasic() +// if res.IsErr() { +// return res.PrependLog("ValidateBasic Failed: ") +// } + +// // TODO - Check whether sufficient funds + +// defer func() { +// // TODO - Refund any remaining funds left over +// // e.g. !ctx.Coins.Minus(tx.Fee).IsZero() +// // ctx.CallerAccount is synced w/ store, so just modify that and store it. +// // NOTE: We should use the CallContext to store fund/refund information. +// }() + +// sm := &IBCStateMachine{store, ctx, abci.OK} + +// switch tx := tx.(type) { +// case IBCRegisterChainTx: +// sm.runRegisterChainTx(tx) +// case IBCUpdateChainTx: +// sm.runUpdateChainTx(tx) +// case IBCPacketCreateTx: +// sm.runPacketCreateTx(tx) +// case IBCPacketPostTx: +// sm.runPacketPostTx(tx) +// } + +// return sm.res +// } + +// type IBCStateMachine struct { +// store types.KVStore +// ctx types.CallContext +// res abci.Result +// } + +// func (sm *IBCStateMachine) runRegisterChainTx(tx IBCRegisterChainTx) { +// chainGenKey := toKey(_IBC, _BLOCKCHAIN, _GENESIS, tx.ChainID) +// chainStateKey := toKey(_IBC, _BLOCKCHAIN, _STATE, tx.ChainID) +// chainGen := tx.BlockchainGenesis + +// // Parse genesis +// chainGenDoc := new(tm.GenesisDoc) +// err := json.Unmarshal([]byte(chainGen.Genesis), chainGenDoc) +// if err != nil { +// sm.res.Code = IBCCodeEncodingError +// sm.res.Log = "Genesis doc couldn't be parsed: " + err.Error() +// return +// } + +// // Make sure chainGen doesn't already exist +// if exists(sm.store, chainGenKey) { +// sm.res.Code = IBCCodeChainAlreadyExists +// sm.res.Log = "Already exists" +// return +// } + +// // Save new BlockchainGenesis +// save(sm.store, chainGenKey, chainGen) + +// // Create new BlockchainState +// chainState := BlockchainState{ +// ChainID: chainGenDoc.ChainID, +// Validators: make([]*tm.Validator, len(chainGenDoc.Validators)), +// LastBlockHash: nil, +// LastBlockHeight: 0, +// } +// // Make validators slice +// for i, val := range chainGenDoc.Validators { +// pubKey := val.PubKey +// address := pubKey.Address() +// chainState.Validators[i] = &tm.Validator{ +// Address: address, +// PubKey: pubKey, +// VotingPower: val.Amount, +// } +// } + +// // Save new BlockchainState +// save(sm.store, chainStateKey, chainState) +// } + +// func (sm *IBCStateMachine) runUpdateChainTx(tx IBCUpdateChainTx) { +// chainID := tx.Header.ChainID +// chainStateKey := toKey(_IBC, _BLOCKCHAIN, _STATE, chainID) + +// // Make sure chainState exists +// if !exists(sm.store, chainStateKey) { +// return // Chain does not exist, do nothing +// } + +// // Load latest chainState +// var chainState BlockchainState +// exists, err := load(sm.store, chainStateKey, &chainState) +// if err != nil { +// sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Loading ChainState: %v", err.Error())) +// return +// } +// if !exists { +// sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Missing ChainState")) +// return +// } + +// // Check commit against last known state & validators +// err = verifyCommit(chainState, &tx.Header, &tx.Commit) +// if err != nil { +// sm.res.Code = IBCCodeInvalidCommit +// sm.res.Log = cmn.Fmt("Invalid Commit: %v", err.Error()) +// return +// } + +// // Store header +// headerKey := toKey(_IBC, _BLOCKCHAIN, _HEADER, chainID, cmn.Fmt("%v", tx.Header.Height)) +// save(sm.store, headerKey, tx.Header) + +// // Update chainState +// chainState.LastBlockHash = tx.Header.Hash() +// chainState.LastBlockHeight = uint64(tx.Header.Height) + +// // Store chainState +// save(sm.store, chainStateKey, chainState) +// } + +// func (sm *IBCStateMachine) runPacketCreateTx(tx IBCPacketCreateTx) { +// packet := tx.Packet +// packetKey := toKey(_IBC, _EGRESS, +// packet.SrcChainID, +// packet.DstChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// // Make sure packet doesn't already exist +// if exists(sm.store, packetKey) { +// sm.res.Code = IBCCodePacketAlreadyExists +// // TODO: .AppendLog() does not update sm.res +// sm.res.Log = "Already exists" +// return +// } + +// // Execute the payload +// switch payload := tx.Packet.Payload.(type) { +// case DataPayload: +// // do nothing +// case CoinsPayload: +// // ensure enough coins were sent in tx to cover the payload coins +// if !sm.ctx.Coins.IsGTE(payload.Coins) { +// sm.res.Code = abci.CodeType_InsufficientFunds +// sm.res.Log = fmt.Sprintf("Not enough funds sent in tx (%v) to send %v via IBC", sm.ctx.Coins, payload.Coins) +// return +// } + +// // deduct coins from context +// sm.ctx.Coins = sm.ctx.Coins.Minus(payload.Coins) +// } + +// // Save new Packet +// save(sm.store, packetKey, packet) + +// // set the sequence number +// SetSequenceNumber(sm.store, packet.SrcChainID, packet.DstChainID, packet.Sequence) +// } + +// func (sm *IBCStateMachine) runPacketPostTx(tx IBCPacketPostTx) { +// packet := tx.Packet +// packetKeyEgress := toKey(_IBC, _EGRESS, +// packet.SrcChainID, +// packet.DstChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// packetKeyIngress := toKey(_IBC, _INGRESS, +// packet.DstChainID, +// packet.SrcChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// headerKey := toKey(_IBC, _BLOCKCHAIN, _HEADER, +// tx.FromChainID, +// cmn.Fmt("%v", tx.FromChainHeight), +// ) + +// // Make sure packet doesn't already exist +// if exists(sm.store, packetKeyIngress) { +// sm.res.Code = IBCCodePacketAlreadyExists +// sm.res.Log = "Already exists" +// return +// } + +// // Save new Packet (just for fun) +// save(sm.store, packetKeyIngress, packet) + +// // Load Header and make sure it exists +// // If it exists, we already checked a valid commit for it in UpdateChainTx +// var header tm.Header +// exists, err := load(sm.store, headerKey, &header) +// if err != nil { +// sm.res = abci.ErrInternalError.AppendLog(cmn.Fmt("Loading Header: %v", err.Error())) +// return +// } +// if !exists { +// sm.res.Code = IBCCodeUnknownHeight +// sm.res.Log = cmn.Fmt("Loading Header: Unknown height") +// return +// } + +// proof := tx.Proof +// if proof == nil { +// sm.res.Code = IBCCodeInvalidProof +// sm.res.Log = "Proof is nil" +// return +// } +// packetBytes := wire.BinaryBytes(packet) + +// // Make sure packet's proof matches given (packet, key, blockhash) +// ok := proof.Verify(packetKeyEgress, packetBytes, header.AppHash) +// if !ok { +// sm.res.Code = IBCCodeInvalidProof +// sm.res.Log = fmt.Sprintf("Proof is invalid. key: %s; packetByes %X; header %v; proof %v", packetKeyEgress, packetBytes, header, proof) +// return +// } + +// // Execute payload +// switch payload := packet.Payload.(type) { +// case DataPayload: +// // do nothing +// case CoinsPayload: +// // Add coins to destination account +// acc := types.GetAccount(sm.store, payload.Address) +// if acc == nil { +// acc = &types.Account{} +// } +// acc.Balance = acc.Balance.Plus(payload.Coins) +// types.SetAccount(sm.store, payload.Address, acc) +// } + +// return +// } + +// func (ibc *IBCPlugin) InitChain(store types.KVStore, vals []*abci.Validator) { +// } + +// func (cp *IBCPlugin) BeginBlock(store types.KVStore, hash []byte, header *abci.Header) { +// } + +// func (cp *IBCPlugin) EndBlock(store types.KVStore, height uint64) (res abci.ResponseEndBlock) { +// return +// } + +// //-------------------------------------------------------------------------------- +// // TODO: move to utils + +// // Returns true if exists, false if nil. +// func exists(store types.KVStore, key []byte) (exists bool) { +// value := store.Get(key) +// return len(value) > 0 +// } + +// // Load bytes from store by reading value for key and read into ptr. +// // Returns true if exists, false if nil. +// // Returns err if decoding error. +// func load(store types.KVStore, key []byte, ptr interface{}) (exists bool, err error) { +// value := store.Get(key) +// if len(value) > 0 { +// err = wire.ReadBinaryBytes(value, ptr) +// if err != nil { +// return true, errors.New( +// cmn.Fmt("Error decoding key 0x%X = 0x%X: %v", key, value, err.Error()), +// ) +// } +// return true, nil +// } else { +// return false, nil +// } +// } + +// // Save bytes to store by writing obj's go-wire binary bytes. +// func save(store types.KVStore, key []byte, obj interface{}) { +// store.Set(key, wire.BinaryBytes(obj)) +// } + +// // Key parts are URL escaped and joined with ',' +// func toKey(parts ...string) []byte { +// escParts := make([]string, len(parts)) +// for i, part := range parts { +// escParts[i] = url.QueryEscape(part) +// } +// return []byte(strings.Join(escParts, ",")) +// } + +// // NOTE: Commit's votes include ValidatorAddress, so can be matched up +// // against chainState.Validators, even if the validator set had changed. +// // For the purpose of the demo, we assume that the validator set hadn't changed, +// // though we should check that explicitly. +// func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Commit) error { + +// // Ensure that chainState and header ChainID match. +// if chainState.ChainID != header.ChainID { +// return errors.New(cmn.Fmt("Expected header.ChainID %v, got %v", chainState.ChainID, header.ChainID)) +// } +// // Ensure things aren't empty +// if len(chainState.Validators) == 0 { +// return errors.New(cmn.Fmt("Blockchain has no validators")) // NOTE: Why would this happen? +// } +// if len(commit.Precommits) == 0 { +// return errors.New(cmn.Fmt("Commit has no signatures")) +// } +// chainID := chainState.ChainID +// vals := chainState.Validators +// valSet := tm.NewValidatorSet(vals) + +// var blockID tm.BlockID +// for _, pc := range commit.Precommits { +// // XXX: incorrect. we want the one for +2/3, not just the first one +// if pc != nil { +// blockID = pc.BlockID +// } +// } +// if blockID.IsZero() { +// return errors.New("All precommits are nil!") +// } + +// // NOTE: Currently this only works with the exact same validator set. +// // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose +// // the functionality to verify commits even after validator changes. +// err := valSet.VerifyCommit(chainID, blockID, header.Height, commit) +// if err != nil { +// return err +// } + +// // Ensure the committed blockID matches the header +// if !bytes.Equal(header.Hash(), blockID.Hash) { +// return errors.New(cmn.Fmt("blockID.Hash (%X) does not match header.Hash (%X)", blockID.Hash, header.Hash())) +// } + +// // All ok! +// return nil +// } diff --git a/plugins/ibc/ibc_test.go b/plugins/ibc/ibc_test.go index 93a913dec0..ffd464843a 100644 --- a/plugins/ibc/ibc_test.go +++ b/plugins/ibc/ibc_test.go @@ -1,512 +1,512 @@ package ibc -import ( - "bytes" - "encoding/json" - "sort" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/go-wire" - eyes "github.com/tendermint/merkleeyes/client" - "github.com/tendermint/merkleeyes/iavl" - cmn "github.com/tendermint/tmlibs/common" - - "github.com/tendermint/basecoin/types" - tm "github.com/tendermint/tendermint/types" -) - -// NOTE: PrivAccounts are sorted by Address, -// GenesisDoc, not necessarily. -func genGenesisDoc(chainID string, numVals int) (*tm.GenesisDoc, []types.PrivAccount) { - var privAccs []types.PrivAccount - genDoc := &tm.GenesisDoc{ - ChainID: chainID, - Validators: nil, - } - - for i := 0; i < numVals; i++ { - name := cmn.Fmt("%v_val_%v", chainID, i) - privAcc := types.PrivAccountFromSecret(name) - genDoc.Validators = append(genDoc.Validators, tm.GenesisValidator{ - PubKey: privAcc.PubKey, - Amount: 1, - Name: name, - }) - privAccs = append(privAccs, privAcc) - } - - // Sort PrivAccounts - sort.Sort(PrivAccountsByAddress(privAccs)) - - return genDoc, privAccs -} - -//------------------------------------- -// Implements sort for sorting PrivAccount by address. - -type PrivAccountsByAddress []types.PrivAccount - -func (pas PrivAccountsByAddress) Len() int { - return len(pas) -} - -func (pas PrivAccountsByAddress) Less(i, j int) bool { - return bytes.Compare(pas[i].Account.PubKey.Address(), pas[j].Account.PubKey.Address()) == -1 -} - -func (pas PrivAccountsByAddress) Swap(i, j int) { - it := pas[i] - pas[i] = pas[j] - pas[j] = it -} - -//-------------------------------------------------------------------------------- - -var testGenesisDoc = `{ - "app_hash": "", - "chain_id": "test_chain_1", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": { - "type": "ed25519", - "data":"D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A" - } - } - ], - "app_options": { - "accounts": [ - { - "pub_key": { - "type": "ed25519", - "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } - ] - } -}` - -func TestIBCGenesisFromString(t *testing.T) { - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - registerChain(t, ibcPlugin, store, ctx, "test_chain", testGenesisDoc) -} - -//-------------------------------------------------------------------------------- - -func TestIBCPluginRegister(t *testing.T) { - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - chainID_1 := "test_chain" - genDoc_1, _ := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Register a malformed chain - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ - BlockchainGenesis{ - ChainID: "test_chain", - Genesis: "", - }, - }})) - assertAndLog(t, store, res, IBCCodeEncodingError) - - // Successfully register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // Duplicate request fails - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ - BlockchainGenesis{ - ChainID: "test_chain", - Genesis: string(genDocJSON_1), - }, - }})) - assertAndLog(t, store, res, IBCCodeChainAlreadyExists) -} - -func TestIBCPluginPost(t *testing.T) { - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - chainID_1 := "test_chain" - genDoc_1, _ := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // Create a new packet (for testing) - packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Post a duplicate packet - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, IBCCodePacketAlreadyExists) -} - -func TestIBCPluginPayloadBytes(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - chainID_1 := "test_chain" - genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // Create a new packet (for testing) - packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Construct a Header that includes the above packet. - store.Sync() - resCommit := eyesClient.CommitSync() - appHash := resCommit.Data - header := newHeader("test_chain", 999, appHash, []byte("must_exist")) - - // Construct a Commit that signs above header - commit := constructCommit(privAccs_1, header) - - // Update a chain - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ - Header: header, - Commit: commit, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Get proof for the packet - packetKey := toKey(_IBC, _EGRESS, - packet.SrcChainID, - packet.DstChainID, - cmn.Fmt("%v", packet.Sequence), - ) - resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ - Path: "/store", - Data: packetKey, - Prove: true, - }) - assert.Nil(err) - var proof *iavl.IAVLProof - err = wire.ReadBinaryBytes(resQuery.Proof, &proof) - assert.Nil(err) - - // Post a packet - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ - FromChainID: "test_chain", - FromChainHeight: 999, - Packet: packet, - Proof: proof, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) -} - -func TestIBCPluginPayloadCoins(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - coins := types.Coins{ - types.Coin{ - Denom: "mycoin", - Amount: 100, - }, - } - ctx := types.NewCallContext(nil, nil, coins) - - chainID_1 := "test_chain" - genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // send coins to this addr on the other chain - destinationAddr := []byte("some address") - coinsBad := types.Coins{types.Coin{"mycoin", 200}} - coinsGood := types.Coins{types.Coin{"mycoin", 1}} - - // Try to send too many coins - packet := NewPacket("test_chain", "dst_chain", 0, CoinsPayload{ - Address: destinationAddr, - Coins: coinsBad, - }) - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, abci.CodeType_InsufficientFunds) - - // Send a small enough number of coins - packet = NewPacket("test_chain", "dst_chain", 0, CoinsPayload{ - Address: destinationAddr, - Coins: coinsGood, - }) - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Construct a Header that includes the above packet. - store.Sync() - resCommit := eyesClient.CommitSync() - appHash := resCommit.Data - header := newHeader("test_chain", 999, appHash, []byte("must_exist")) - - // Construct a Commit that signs above header - commit := constructCommit(privAccs_1, header) - - // Update a chain - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ - Header: header, - Commit: commit, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Get proof for the packet - packetKey := toKey(_IBC, _EGRESS, - packet.SrcChainID, - packet.DstChainID, - cmn.Fmt("%v", packet.Sequence), - ) - resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ - Path: "/store", - Data: packetKey, - Prove: true, - }) - assert.Nil(err) - var proof *iavl.IAVLProof - err = wire.ReadBinaryBytes(resQuery.Proof, &proof) - assert.Nil(err) - - // Account should be empty before the tx - acc := types.GetAccount(store, destinationAddr) - assert.Nil(acc) - - // Post a packet - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ - FromChainID: "test_chain", - FromChainHeight: 999, - Packet: packet, - Proof: proof, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Account should now have some coins - acc = types.GetAccount(store, destinationAddr) - assert.Equal(acc.Balance, coinsGood) -} - -func TestIBCPluginBadCommit(t *testing.T) { - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - chainID_1 := "test_chain" - genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Successfully register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // Construct a Header - header := newHeader("test_chain", 999, nil, []byte("must_exist")) - - // Construct a Commit that signs above header - commit := constructCommit(privAccs_1, header) - - // Update a chain with a broken commit - // Modify the first byte of the first signature - sig := commit.Precommits[0].Signature.Unwrap().(crypto.SignatureEd25519) - sig[0] += 1 - commit.Precommits[0].Signature = sig.Wrap() - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ - Header: header, - Commit: commit, - }})) - assertAndLog(t, store, res, IBCCodeInvalidCommit) - -} - -func TestIBCPluginBadProof(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - eyesClient := eyes.NewLocalClient("", 0) - store := types.NewKVCache(eyesClient) - store.SetLogging() // Log all activity - - ibcPlugin := New() - ctx := types.NewCallContext(nil, nil, types.Coins{}) - - chainID_1 := "test_chain" - genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) - genDocJSON_1, err := json.Marshal(genDoc_1) - require.Nil(err) - - // Successfully register a chain - registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) - - // Create a new packet (for testing) - packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ - Packet: packet, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Construct a Header that includes the above packet. - store.Sync() - resCommit := eyesClient.CommitSync() - appHash := resCommit.Data - header := newHeader("test_chain", 999, appHash, []byte("must_exist")) - - // Construct a Commit that signs above header - commit := constructCommit(privAccs_1, header) - - // Update a chain - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ - Header: header, - Commit: commit, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) - - // Get proof for the packet - packetKey := toKey(_IBC, _EGRESS, - packet.SrcChainID, - packet.DstChainID, - cmn.Fmt("%v", packet.Sequence), - ) - resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ - Path: "/store", - Data: packetKey, - Prove: true, - }) - assert.Nil(err) - var proof *iavl.IAVLProof - err = wire.ReadBinaryBytes(resQuery.Proof, &proof) - assert.Nil(err) - - // Mutate the proof - proof.InnerNodes[0].Height += 1 - - // Post a packet - res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ - FromChainID: "test_chain", - FromChainHeight: 999, - Packet: packet, - Proof: proof, - }})) - assertAndLog(t, store, res, IBCCodeInvalidProof) -} - -//------------------------------------- -// utils - -func assertAndLog(t *testing.T, store *types.KVCache, res abci.Result, codeExpected abci.CodeType) { - assert := assert.New(t) - assert.Equal(codeExpected, res.Code, res.Log) - t.Log(">>", strings.Join(store.GetLogLines(), "\n")) - store.ClearLogLines() -} - -func newHeader(chainID string, height int, appHash, valHash []byte) tm.Header { - return tm.Header{ - ChainID: chainID, - Height: height, - AppHash: appHash, - ValidatorsHash: valHash, - } -} - -func registerChain(t *testing.T, ibcPlugin *IBCPlugin, store *types.KVCache, ctx types.CallContext, chainID, genDoc string) { - res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ - BlockchainGenesis{ - ChainID: chainID, - Genesis: genDoc, - }, - }})) - assertAndLog(t, store, res, abci.CodeType_OK) -} - -func constructCommit(privAccs []types.PrivAccount, header tm.Header) tm.Commit { - blockHash := header.Hash() - blockID := tm.BlockID{Hash: blockHash} - commit := tm.Commit{ - BlockID: blockID, - Precommits: make([]*tm.Vote, len(privAccs)), - } - for i, privAcc := range privAccs { - vote := &tm.Vote{ - ValidatorAddress: privAcc.Account.PubKey.Address(), - ValidatorIndex: i, - Height: 999, - Round: 0, - Type: tm.VoteTypePrecommit, - BlockID: tm.BlockID{Hash: blockHash}, - } - vote.Signature = privAcc.PrivKey.Sign( - tm.SignBytes("test_chain", vote), - ) - commit.Precommits[i] = vote - } - return commit -} +// import ( +// "bytes" +// "encoding/json" +// "sort" +// "strings" +// "testing" + +// "github.com/stretchr/testify/assert" +// "github.com/stretchr/testify/require" + +// abci "github.com/tendermint/abci/types" +// crypto "github.com/tendermint/go-crypto" +// "github.com/tendermint/go-wire" +// eyes "github.com/tendermint/merkleeyes/client" +// "github.com/tendermint/merkleeyes/iavl" +// cmn "github.com/tendermint/tmlibs/common" + +// "github.com/tendermint/basecoin/types" +// tm "github.com/tendermint/tendermint/types" +// ) + +// // NOTE: PrivAccounts are sorted by Address, +// // GenesisDoc, not necessarily. +// func genGenesisDoc(chainID string, numVals int) (*tm.GenesisDoc, []types.PrivAccount) { +// var privAccs []types.PrivAccount +// genDoc := &tm.GenesisDoc{ +// ChainID: chainID, +// Validators: nil, +// } + +// for i := 0; i < numVals; i++ { +// name := cmn.Fmt("%v_val_%v", chainID, i) +// privAcc := types.PrivAccountFromSecret(name) +// genDoc.Validators = append(genDoc.Validators, tm.GenesisValidator{ +// PubKey: privAcc.PubKey, +// Amount: 1, +// Name: name, +// }) +// privAccs = append(privAccs, privAcc) +// } + +// // Sort PrivAccounts +// sort.Sort(PrivAccountsByAddress(privAccs)) + +// return genDoc, privAccs +// } + +// //------------------------------------- +// // Implements sort for sorting PrivAccount by address. + +// type PrivAccountsByAddress []types.PrivAccount + +// func (pas PrivAccountsByAddress) Len() int { +// return len(pas) +// } + +// func (pas PrivAccountsByAddress) Less(i, j int) bool { +// return bytes.Compare(pas[i].Account.PubKey.Address(), pas[j].Account.PubKey.Address()) == -1 +// } + +// func (pas PrivAccountsByAddress) Swap(i, j int) { +// it := pas[i] +// pas[i] = pas[j] +// pas[j] = it +// } + +// //-------------------------------------------------------------------------------- + +// var testGenesisDoc = `{ +// "app_hash": "", +// "chain_id": "test_chain_1", +// "genesis_time": "0001-01-01T00:00:00.000Z", +// "validators": [ +// { +// "amount": 10, +// "name": "", +// "pub_key": { +// "type": "ed25519", +// "data":"D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A" +// } +// } +// ], +// "app_options": { +// "accounts": [ +// { +// "pub_key": { +// "type": "ed25519", +// "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" +// }, +// "coins": [ +// { +// "denom": "mycoin", +// "amount": 9007199254740992 +// } +// ] +// } +// ] +// } +// }` + +// func TestIBCGenesisFromString(t *testing.T) { +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// registerChain(t, ibcPlugin, store, ctx, "test_chain", testGenesisDoc) +// } + +// //-------------------------------------------------------------------------------- + +// func TestIBCPluginRegister(t *testing.T) { +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// chainID_1 := "test_chain" +// genDoc_1, _ := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Register a malformed chain +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ +// BlockchainGenesis{ +// ChainID: "test_chain", +// Genesis: "", +// }, +// }})) +// assertAndLog(t, store, res, IBCCodeEncodingError) + +// // Successfully register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // Duplicate request fails +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ +// BlockchainGenesis{ +// ChainID: "test_chain", +// Genesis: string(genDocJSON_1), +// }, +// }})) +// assertAndLog(t, store, res, IBCCodeChainAlreadyExists) +// } + +// func TestIBCPluginPost(t *testing.T) { +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// chainID_1 := "test_chain" +// genDoc_1, _ := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // Create a new packet (for testing) +// packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Post a duplicate packet +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, IBCCodePacketAlreadyExists) +// } + +// func TestIBCPluginPayloadBytes(t *testing.T) { +// assert := assert.New(t) +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// chainID_1 := "test_chain" +// genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // Create a new packet (for testing) +// packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Construct a Header that includes the above packet. +// store.Sync() +// resCommit := eyesClient.CommitSync() +// appHash := resCommit.Data +// header := newHeader("test_chain", 999, appHash, []byte("must_exist")) + +// // Construct a Commit that signs above header +// commit := constructCommit(privAccs_1, header) + +// // Update a chain +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ +// Header: header, +// Commit: commit, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Get proof for the packet +// packetKey := toKey(_IBC, _EGRESS, +// packet.SrcChainID, +// packet.DstChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ +// Path: "/store", +// Data: packetKey, +// Prove: true, +// }) +// assert.Nil(err) +// var proof *iavl.IAVLProof +// err = wire.ReadBinaryBytes(resQuery.Proof, &proof) +// assert.Nil(err) + +// // Post a packet +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ +// FromChainID: "test_chain", +// FromChainHeight: 999, +// Packet: packet, +// Proof: proof, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) +// } + +// func TestIBCPluginPayloadCoins(t *testing.T) { +// assert := assert.New(t) +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// coins := types.Coins{ +// types.Coin{ +// Denom: "mycoin", +// Amount: 100, +// }, +// } +// ctx := types.NewCallContext(nil, nil, coins) + +// chainID_1 := "test_chain" +// genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // send coins to this addr on the other chain +// destinationAddr := []byte("some address") +// coinsBad := types.Coins{types.Coin{"mycoin", 200}} +// coinsGood := types.Coins{types.Coin{"mycoin", 1}} + +// // Try to send too many coins +// packet := NewPacket("test_chain", "dst_chain", 0, CoinsPayload{ +// Address: destinationAddr, +// Coins: coinsBad, +// }) +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, abci.CodeType_InsufficientFunds) + +// // Send a small enough number of coins +// packet = NewPacket("test_chain", "dst_chain", 0, CoinsPayload{ +// Address: destinationAddr, +// Coins: coinsGood, +// }) +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Construct a Header that includes the above packet. +// store.Sync() +// resCommit := eyesClient.CommitSync() +// appHash := resCommit.Data +// header := newHeader("test_chain", 999, appHash, []byte("must_exist")) + +// // Construct a Commit that signs above header +// commit := constructCommit(privAccs_1, header) + +// // Update a chain +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ +// Header: header, +// Commit: commit, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Get proof for the packet +// packetKey := toKey(_IBC, _EGRESS, +// packet.SrcChainID, +// packet.DstChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ +// Path: "/store", +// Data: packetKey, +// Prove: true, +// }) +// assert.Nil(err) +// var proof *iavl.IAVLProof +// err = wire.ReadBinaryBytes(resQuery.Proof, &proof) +// assert.Nil(err) + +// // Account should be empty before the tx +// acc := types.GetAccount(store, destinationAddr) +// assert.Nil(acc) + +// // Post a packet +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ +// FromChainID: "test_chain", +// FromChainHeight: 999, +// Packet: packet, +// Proof: proof, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Account should now have some coins +// acc = types.GetAccount(store, destinationAddr) +// assert.Equal(acc.Balance, coinsGood) +// } + +// func TestIBCPluginBadCommit(t *testing.T) { +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// chainID_1 := "test_chain" +// genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Successfully register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // Construct a Header +// header := newHeader("test_chain", 999, nil, []byte("must_exist")) + +// // Construct a Commit that signs above header +// commit := constructCommit(privAccs_1, header) + +// // Update a chain with a broken commit +// // Modify the first byte of the first signature +// sig := commit.Precommits[0].Signature.Unwrap().(crypto.SignatureEd25519) +// sig[0] += 1 +// commit.Precommits[0].Signature = sig.Wrap() +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ +// Header: header, +// Commit: commit, +// }})) +// assertAndLog(t, store, res, IBCCodeInvalidCommit) + +// } + +// func TestIBCPluginBadProof(t *testing.T) { +// assert := assert.New(t) +// require := require.New(t) + +// eyesClient := eyes.NewLocalClient("", 0) +// store := types.NewKVCache(eyesClient) +// store.SetLogging() // Log all activity + +// ibcPlugin := New() +// ctx := types.NewCallContext(nil, nil, types.Coins{}) + +// chainID_1 := "test_chain" +// genDoc_1, privAccs_1 := genGenesisDoc(chainID_1, 4) +// genDocJSON_1, err := json.Marshal(genDoc_1) +// require.Nil(err) + +// // Successfully register a chain +// registerChain(t, ibcPlugin, store, ctx, "test_chain", string(genDocJSON_1)) + +// // Create a new packet (for testing) +// packet := NewPacket("test_chain", "dst_chain", 0, DataPayload([]byte("hello world"))) +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketCreateTx{ +// Packet: packet, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Construct a Header that includes the above packet. +// store.Sync() +// resCommit := eyesClient.CommitSync() +// appHash := resCommit.Data +// header := newHeader("test_chain", 999, appHash, []byte("must_exist")) + +// // Construct a Commit that signs above header +// commit := constructCommit(privAccs_1, header) + +// // Update a chain +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCUpdateChainTx{ +// Header: header, +// Commit: commit, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) + +// // Get proof for the packet +// packetKey := toKey(_IBC, _EGRESS, +// packet.SrcChainID, +// packet.DstChainID, +// cmn.Fmt("%v", packet.Sequence), +// ) +// resQuery, err := eyesClient.QuerySync(abci.RequestQuery{ +// Path: "/store", +// Data: packetKey, +// Prove: true, +// }) +// assert.Nil(err) +// var proof *iavl.IAVLProof +// err = wire.ReadBinaryBytes(resQuery.Proof, &proof) +// assert.Nil(err) + +// // Mutate the proof +// proof.InnerNodes[0].Height += 1 + +// // Post a packet +// res = ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCPacketPostTx{ +// FromChainID: "test_chain", +// FromChainHeight: 999, +// Packet: packet, +// Proof: proof, +// }})) +// assertAndLog(t, store, res, IBCCodeInvalidProof) +// } + +// //------------------------------------- +// // utils + +// func assertAndLog(t *testing.T, store *types.KVCache, res abci.Result, codeExpected abci.CodeType) { +// assert := assert.New(t) +// assert.Equal(codeExpected, res.Code, res.Log) +// t.Log(">>", strings.Join(store.GetLogLines(), "\n")) +// store.ClearLogLines() +// } + +// func newHeader(chainID string, height int, appHash, valHash []byte) tm.Header { +// return tm.Header{ +// ChainID: chainID, +// Height: height, +// AppHash: appHash, +// ValidatorsHash: valHash, +// } +// } + +// func registerChain(t *testing.T, ibcPlugin *IBCPlugin, store *types.KVCache, ctx types.CallContext, chainID, genDoc string) { +// res := ibcPlugin.RunTx(store, ctx, wire.BinaryBytes(struct{ IBCTx }{IBCRegisterChainTx{ +// BlockchainGenesis{ +// ChainID: chainID, +// Genesis: genDoc, +// }, +// }})) +// assertAndLog(t, store, res, abci.CodeType_OK) +// } + +// func constructCommit(privAccs []types.PrivAccount, header tm.Header) tm.Commit { +// blockHash := header.Hash() +// blockID := tm.BlockID{Hash: blockHash} +// commit := tm.Commit{ +// BlockID: blockID, +// Precommits: make([]*tm.Vote, len(privAccs)), +// } +// for i, privAcc := range privAccs { +// vote := &tm.Vote{ +// ValidatorAddress: privAcc.Account.PubKey.Address(), +// ValidatorIndex: i, +// Height: 999, +// Round: 0, +// Type: tm.VoteTypePrecommit, +// BlockID: tm.BlockID{Hash: blockHash}, +// } +// vote.Signature = privAcc.PrivKey.Sign( +// tm.SignBytes("test_chain", vote), +// ) +// commit.Precommits[i] = vote +// } +// return commit +// } diff --git a/state/execution.go b/state/execution.go deleted file mode 100644 index 307c0d463c..0000000000 --- a/state/execution.go +++ /dev/null @@ -1,310 +0,0 @@ -package state - -import ( - abci "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/events" - - "github.com/tendermint/basecoin/plugins/ibc" - "github.com/tendermint/basecoin/types" -) - -// If the tx is invalid, a TMSP error will be returned. -func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc events.Fireable) abci.Result { - chainID := state.GetChainID() - - // Exec tx - switch tx := tx.(type) { - case *types.SendTx: - // Validate inputs and outputs, basic - res := validateInputsBasic(tx.Inputs) - if res.IsErr() { - return res.PrependLog("in validateInputsBasic()") - } - res = validateOutputsBasic(tx.Outputs) - if res.IsErr() { - return res.PrependLog("in validateOutputsBasic()") - } - - // Get inputs - accounts, res := getInputs(state, tx.Inputs) - if res.IsErr() { - return res.PrependLog("in getInputs()") - } - - // Get or make outputs. - accounts, res = getOrMakeOutputs(state, accounts, tx.Outputs) - if res.IsErr() { - return res.PrependLog("in getOrMakeOutputs()") - } - - // Validate inputs and outputs, advanced - signBytes := tx.SignBytes(chainID) - inTotal, res := validateInputsAdvanced(accounts, signBytes, tx.Inputs) - if res.IsErr() { - return res.PrependLog("in validateInputsAdvanced()") - } - outTotal := sumOutputs(tx.Outputs) - outPlusFees := outTotal - fees := types.Coins{tx.Fee} - if fees.IsValid() { // TODO: fix coins.Plus() - outPlusFees = outTotal.Plus(fees) - } - if !inTotal.IsEqual(outPlusFees) { - return abci.ErrBaseInvalidOutput.AppendLog(cmn.Fmt("Input total (%v) != output total + fees (%v)", inTotal, outPlusFees)) - } - - // TODO: Fee validation for SendTx - - // Good! Adjust accounts - adjustByInputs(state, accounts, tx.Inputs) - adjustByOutputs(state, accounts, tx.Outputs, isCheckTx) - - /* - // Fire events - if !isCheckTx { - if evc != nil { - for _, i := range tx.Inputs { - evc.FireEvent(types.EventStringAccInput(i.Address), types.EventDataTx{tx, nil, ""}) - } - for _, o := range tx.Outputs { - evc.FireEvent(types.EventStringAccOutput(o.Address), types.EventDataTx{tx, nil, ""}) - } - } - } - */ - - return abci.NewResultOK(types.TxID(chainID, tx), "") - - case *types.AppTx: - // Validate input, basic - res := tx.Input.ValidateBasic() - if res.IsErr() { - return res - } - - // Get input account - inAcc := state.GetAccount(tx.Input.Address) - if inAcc == nil { - return abci.ErrBaseUnknownAddress - } - if !tx.Input.PubKey.Empty() { - inAcc.PubKey = tx.Input.PubKey - } - - // Validate input, advanced - signBytes := tx.SignBytes(chainID) - res = validateInputAdvanced(inAcc, signBytes, tx.Input) - if res.IsErr() { - state.logger.Info(cmn.Fmt("validateInputAdvanced failed on %X: %v", tx.Input.Address, res)) - return res.PrependLog("in validateInputAdvanced()") - } - if !tx.Input.Coins.IsGTE(types.Coins{tx.Fee}) { - state.logger.Info(cmn.Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) - return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("input coins is %v, but fee is %v", tx.Input.Coins, types.Coins{tx.Fee})) - } - - // Validate call address - plugin := pgz.GetByName(tx.Name) - if plugin == nil { - return abci.ErrBaseUnknownAddress.AppendLog( - cmn.Fmt("Unrecognized plugin name%v", tx.Name)) - } - - // Good! - coins := tx.Input.Coins.Minus(types.Coins{tx.Fee}) - inAcc.Sequence += 1 - inAcc.Balance = inAcc.Balance.Minus(tx.Input.Coins) - - // If this is a CheckTx, stop now. - if isCheckTx { - state.SetAccount(tx.Input.Address, inAcc) - return abci.OK - } - - // Create inAcc checkpoint - inAccCopy := inAcc.Copy() - - // Run the tx. - cache := state.CacheWrap() - cache.SetAccount(tx.Input.Address, inAcc) - ctx := types.NewCallContext(tx.Input.Address, inAcc, coins) - res = plugin.RunTx(cache, ctx, tx.Data) - if res.IsOK() { - cache.CacheSync() - state.logger.Info("Successful execution") - // Fire events - /* - if evc != nil { - exception := "" - if res.IsErr() { - exception = res.Error() - } - evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventDataTx{tx, ret, exception}) - evc.FireEvent(types.EventStringAccOutput(tx.Address), types.EventDataTx{tx, ret, exception}) - } - */ - } else { - state.logger.Info("AppTx failed", "error", res) - // Just return the coins and return. - inAccCopy.Balance = inAccCopy.Balance.Plus(coins) - // But take the gas - // TODO - state.SetAccount(tx.Input.Address, inAccCopy) - } - return res - - default: - return abci.ErrBaseEncodingError.SetLog("Unknown tx type") - } -} - -//-------------------------------------------------------------------------------- - -// The accounts from the TxInputs must either already have -// crypto.PubKey.(type) != nil, (it must be known), -// or it must be specified in the TxInput. -func getInputs(state types.AccountGetter, ins []types.TxInput) (map[string]*types.Account, abci.Result) { - accounts := map[string]*types.Account{} - for _, in := range ins { - // Account shouldn't be duplicated - if _, ok := accounts[string(in.Address)]; ok { - return nil, abci.ErrBaseDuplicateAddress - } - - acc := state.GetAccount(in.Address) - if acc == nil { - return nil, abci.ErrBaseUnknownAddress - } - - if !in.PubKey.Empty() { - acc.PubKey = in.PubKey - } - accounts[string(in.Address)] = acc - } - return accounts, abci.OK -} - -func getOrMakeOutputs(state types.AccountGetter, accounts map[string]*types.Account, outs []types.TxOutput) (map[string]*types.Account, abci.Result) { - if accounts == nil { - accounts = make(map[string]*types.Account) - } - - for _, out := range outs { - chain, outAddress, _ := out.ChainAndAddress() // already validated - if chain != nil { - // we dont need an account for the other chain. - // we'll just create an outgoing ibc packet - continue - } - // Account shouldn't be duplicated - if _, ok := accounts[string(outAddress)]; ok { - return nil, abci.ErrBaseDuplicateAddress - } - acc := state.GetAccount(outAddress) - // output account may be nil (new) - if acc == nil { - // zero value is valid, empty account - acc = &types.Account{} - } - accounts[string(outAddress)] = acc - } - return accounts, abci.OK -} - -// Validate inputs basic structure -func validateInputsBasic(ins []types.TxInput) (res abci.Result) { - for _, in := range ins { - // Check TxInput basic - if res := in.ValidateBasic(); res.IsErr() { - return res - } - } - return abci.OK -} - -// Validate inputs and compute total amount of coins -func validateInputsAdvanced(accounts map[string]*types.Account, signBytes []byte, ins []types.TxInput) (total types.Coins, res abci.Result) { - for _, in := range ins { - acc := accounts[string(in.Address)] - if acc == nil { - cmn.PanicSanity("validateInputsAdvanced() expects account in accounts") - } - res = validateInputAdvanced(acc, signBytes, in) - if res.IsErr() { - return - } - // Good. Add amount to total - total = total.Plus(in.Coins) - } - return total, abci.OK -} - -func validateInputAdvanced(acc *types.Account, signBytes []byte, in types.TxInput) (res abci.Result) { - // Check sequence/coins - seq, balance := acc.Sequence, acc.Balance - if seq+1 != in.Sequence { - return abci.ErrBaseInvalidSequence.AppendLog(cmn.Fmt("Got %v, expected %v. (acc.seq=%v)", in.Sequence, seq+1, acc.Sequence)) - } - // Check amount - if !balance.IsGTE(in.Coins) { - return abci.ErrBaseInsufficientFunds.AppendLog(cmn.Fmt("balance is %v, tried to send %v", balance, in.Coins)) - } - // Check signatures - if !acc.PubKey.VerifyBytes(signBytes, in.Signature) { - return abci.ErrBaseInvalidSignature.AppendLog(cmn.Fmt("SignBytes: %X", signBytes)) - } - return abci.OK -} - -func validateOutputsBasic(outs []types.TxOutput) (res abci.Result) { - for _, out := range outs { - // Check TxOutput basic - if res := out.ValidateBasic(); res.IsErr() { - return res - } - } - return abci.OK -} - -func sumOutputs(outs []types.TxOutput) (total types.Coins) { - for _, out := range outs { - total = total.Plus(out.Coins) - } - return total -} - -func adjustByInputs(state types.AccountSetter, accounts map[string]*types.Account, ins []types.TxInput) { - for _, in := range ins { - acc := accounts[string(in.Address)] - if acc == nil { - cmn.PanicSanity("adjustByInputs() expects account in accounts") - } - if !acc.Balance.IsGTE(in.Coins) { - cmn.PanicSanity("adjustByInputs() expects sufficient funds") - } - acc.Balance = acc.Balance.Minus(in.Coins) - acc.Sequence += 1 - state.SetAccount(in.Address, acc) - } -} - -func adjustByOutputs(state *State, accounts map[string]*types.Account, outs []types.TxOutput, isCheckTx bool) { - for _, out := range outs { - destChain, outAddress, _ := out.ChainAndAddress() // already validated - if destChain != nil { - payload := ibc.CoinsPayload{outAddress, out.Coins} - ibc.SaveNewIBCPacket(state, state.GetChainID(), string(destChain), payload) - continue - } - - acc := accounts[string(outAddress)] - if acc == nil { - cmn.PanicSanity("adjustByOutputs() expects account in accounts") - } - acc.Balance = acc.Balance.Plus(out.Coins) - if !isCheckTx { - state.SetAccount(outAddress, acc) - } - } -} diff --git a/state/execution_test.go b/state/execution_test.go deleted file mode 100644 index 983ae8d599..0000000000 --- a/state/execution_test.go +++ /dev/null @@ -1,365 +0,0 @@ -package state - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/log" - - "github.com/tendermint/basecoin/plugins/ibc" - "github.com/tendermint/basecoin/types" -) - -//-------------------------------------------------------- -// test environment is a bunch of lists of accountns - -type execTest struct { - chainID string - store types.KVStore - state *State - accIn types.PrivAccount - accOut types.PrivAccount -} - -func newExecTest() *execTest { - et := &execTest{ - chainID: "test_chain_id", - } - et.reset() - return et -} - -func (et *execTest) signTx(tx *types.SendTx, accsIn ...types.PrivAccount) { - types.SignTx(et.chainID, tx, accsIn...) -} - -// returns the final balance and expected balance for input and output accounts -func (et *execTest) exec(tx *types.SendTx, checkTx bool) (res abci.Result, inGot, inExp, outGot, outExp types.Coins) { - initBalIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance - initBalOut := et.state.GetAccount(et.accOut.Account.PubKey.Address()).Balance - - res = ExecTx(et.state, nil, tx, checkTx, nil) - - endBalIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance - endBalOut := et.state.GetAccount(et.accOut.Account.PubKey.Address()).Balance - decrBalInExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) //expected decrease in balance In - return res, endBalIn, initBalIn.Minus(decrBalInExp), endBalOut, initBalOut.Plus(tx.Outputs[0].Coins) -} - -func (et *execTest) acc2State(accs ...types.PrivAccount) { - for _, acc := range accs { - et.state.SetAccount(acc.Account.PubKey.Address(), &acc.Account) - } -} - -//reset everything. state is empty -func (et *execTest) reset() { - et.accIn = types.MakeAcc("foo") - et.accOut = types.MakeAcc("bar") - - et.store = types.NewMemKVStore() - et.state = NewState(et.store, log.TestingLogger()) - et.state.SetChainID(et.chainID) - - // NOTE we dont run acc2State here - // so we can test non-existing accounts - -} - -//-------------------------------------------------------- - -func TestGetInputs(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //nil submissions - acc, res := getInputs(nil, nil) - assert.True(res.IsOK(), "getInputs: error on nil submission") - assert.Zero(len(acc), "getInputs: accounts returned on nil submission") - - //test getInputs for registered, non-registered account - et.reset() - inputs := types.Accs2TxInputs(1, et.accIn) - acc, res = getInputs(et.state, inputs) - assert.True(res.IsErr(), "getInputs: expected error when using getInput with non-registered Input") - - et.acc2State(et.accIn) - acc, res = getInputs(et.state, inputs) - assert.True(res.IsOK(), "getInputs: expected to getInput from registered Input") - - //test sending duplicate accounts - et.reset() - et.acc2State(et.accIn, et.accIn, et.accIn) - inputs = types.Accs2TxInputs(1, et.accIn, et.accIn, et.accIn) - acc, res = getInputs(et.state, inputs) - assert.True(res.IsErr(), "getInputs: expected error when sending duplicate accounts") -} - -func TestGetOrMakeOutputs(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //nil submissions - acc, res := getOrMakeOutputs(nil, nil, nil) - assert.True(res.IsOK(), "getOrMakeOutputs: error on nil submission") - assert.Zero(len(acc), "getOrMakeOutputs: accounts returned on nil submission") - - //test sending duplicate accounts - et.reset() - outputs := types.Accs2TxOutputs(et.accIn, et.accIn, et.accIn) - _, res = getOrMakeOutputs(et.state, nil, outputs) - assert.True(res.IsErr(), "getOrMakeOutputs: expected error when sending duplicate accounts") - - //test sending to existing/new account - et.reset() - outputs1 := types.Accs2TxOutputs(et.accIn) - outputs2 := types.Accs2TxOutputs(et.accOut) - - et.acc2State(et.accIn) - _, res = getOrMakeOutputs(et.state, nil, outputs1) - assert.True(res.IsOK(), "getOrMakeOutputs: error when sending to existing account") - - mapRes2, res := getOrMakeOutputs(et.state, nil, outputs2) - assert.True(res.IsOK(), "getOrMakeOutputs: error when sending to new account") - - //test the map results - _, map2ok := mapRes2[string(outputs2[0].Address)] - assert.True(map2ok, "getOrMakeOutputs: account output does not contain new account map item") - -} - -func TestValidateInputsBasic(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //validate input basic - inputs := types.Accs2TxInputs(1, et.accIn) - res := validateInputsBasic(inputs) - assert.True(res.IsOK(), "validateInputsBasic: expected no error on good tx input. Error: %v", res.Error()) - - inputs[0].Coins[0].Amount = 0 - res = validateInputsBasic(inputs) - assert.True(res.IsErr(), "validateInputsBasic: expected error on bad tx input") - -} - -func TestValidateInputsAdvanced(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //create three temp accounts for the test - accIn1 := types.MakeAcc("foox") - accIn2 := types.MakeAcc("fooy") - accIn3 := types.MakeAcc("fooz") - - //validate inputs advanced - tx := types.MakeSendTx(1, et.accOut, accIn1, accIn2, accIn3) - - et.acc2State(accIn1, accIn2, accIn3, et.accOut) - accMap, res := getInputs(et.state, tx.Inputs) - assert.True(res.IsOK(), "validateInputsAdvanced: error retrieving accMap. Error: %v", res.Error()) - signBytes := tx.SignBytes(et.chainID) - - //test bad case, unsigned - totalCoins, res := validateInputsAdvanced(accMap, signBytes, tx.Inputs) - assert.True(res.IsErr(), "validateInputsAdvanced: expected an error on an unsigned tx input") - - //test good case sgined - et.signTx(tx, accIn1, accIn2, accIn3, et.accOut) - totalCoins, res = validateInputsAdvanced(accMap, signBytes, tx.Inputs) - assert.True(res.IsOK(), "validateInputsAdvanced: expected no error on good tx input. Error: %v", res.Error()) - - txTotalCoins := tx.Inputs[0].Coins. - Plus(tx.Inputs[1].Coins). - Plus(tx.Inputs[2].Coins) - - assert.True(totalCoins.IsEqual(txTotalCoins), - "ValidateInputsAdvanced: transaction total coins are not equal: got %v, expected %v", txTotalCoins, totalCoins) -} - -func TestValidateInputAdvanced(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //validate input advanced - tx := types.MakeSendTx(1, et.accOut, et.accIn) - - et.acc2State(et.accIn, et.accOut) - signBytes := tx.SignBytes(et.chainID) - - //unsigned case - res := validateInputAdvanced(&et.accIn.Account, signBytes, tx.Inputs[0]) - assert.True(res.IsErr(), "validateInputAdvanced: expected error on tx input without signature") - - //good signed case - et.signTx(tx, et.accIn, et.accOut) - res = validateInputAdvanced(&et.accIn.Account, signBytes, tx.Inputs[0]) - assert.True(res.IsOK(), "validateInputAdvanced: expected no error on good tx input. Error: %v", res.Error()) - - //bad sequence case - et.accIn.Sequence = 1 - et.signTx(tx, et.accIn, et.accOut) - res = validateInputAdvanced(&et.accIn.Account, signBytes, tx.Inputs[0]) - assert.Equal(abci.CodeType_BaseInvalidSequence, res.Code, "validateInputAdvanced: expected error on tx input with bad sequence") - et.accIn.Sequence = 0 //restore sequence - - //bad balance case - et.accIn.Balance = types.Coins{{"mycoin", 2}} - et.signTx(tx, et.accIn, et.accOut) - res = validateInputAdvanced(&et.accIn.Account, signBytes, tx.Inputs[0]) - assert.Equal(abci.CodeType_BaseInsufficientFunds, res.Code, - "validateInputAdvanced: expected error on tx input with insufficient funds %v", et.accIn.Sequence) -} - -func TestValidateOutputsAdvanced(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //validateOutputsBasic - tx := types.Accs2TxOutputs(et.accIn) - res := validateOutputsBasic(tx) - assert.True(res.IsOK(), "validateOutputsBasic: expected no error on good tx output. Error: %v", res.Error()) - - tx[0].Coins[0].Amount = 0 - res = validateOutputsBasic(tx) - assert.True(res.IsErr(), "validateInputBasic: expected error on bad tx output. Error: %v", res.Error()) -} - -func TestSumOutput(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //SumOutput - tx := types.Accs2TxOutputs(et.accIn, et.accOut) - total := sumOutputs(tx) - assert.True(total.IsEqual(tx[0].Coins.Plus(tx[1].Coins)), "sumOutputs: total coins are not equal") -} - -func TestAdjustBy(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //adjustByInputs/adjustByOutputs - //sending transaction from accIn to accOut - initBalIn := et.accIn.Account.Balance - initBalOut := et.accOut.Account.Balance - et.acc2State(et.accIn, et.accOut) - - txIn := types.Accs2TxInputs(1, et.accIn) - txOut := types.Accs2TxOutputs(et.accOut) - accMap, _ := getInputs(et.state, txIn) - accMap, _ = getOrMakeOutputs(et.state, accMap, txOut) - - adjustByInputs(et.state, accMap, txIn) - adjustByOutputs(et.state, accMap, txOut, false) - - endBalIn := accMap[string(et.accIn.Account.PubKey.Address())].Balance - endBalOut := accMap[string(et.accOut.Account.PubKey.Address())].Balance - decrBalIn := initBalIn.Minus(endBalIn) - incrBalOut := endBalOut.Minus(initBalOut) - - assert.True(decrBalIn.IsEqual(txIn[0].Coins), - "adjustByInputs: total coins are not equal. diff: %v, tx: %v", decrBalIn.String(), txIn[0].Coins.String()) - assert.True(incrBalOut.IsEqual(txOut[0].Coins), - "adjustByInputs: total coins are not equal. diff: %v, tx: %v", incrBalOut.String(), txOut[0].Coins.String()) - -} - -func TestSendTx(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //ExecTx - tx := types.MakeSendTx(1, et.accOut, et.accIn) - et.acc2State(et.accIn) - et.acc2State(et.accOut) - et.signTx(tx, et.accIn) - - //Bad Balance - et.accIn.Balance = types.Coins{{"mycoin", 2}} - et.acc2State(et.accIn) - res, _, _, _, _ := et.exec(tx, true) - assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res) - - res, balIn, balInExp, balOut, balOutExp := et.exec(tx, false) - assert.True(res.IsErr(), "ExecTx/Bad DeliverTx: Expected error return from ExecTx, returned: %v", res) - assert.False(balIn.IsEqual(balInExp), - "ExecTx/Bad DeliverTx: balance shouldn't be equal for accIn: got %v, expected: %v", balIn, balInExp) - assert.False(balOut.IsEqual(balOutExp), - "ExecTx/Bad DeliverTx: balance shouldn't be equal for accOut: got %v, expected: %v", balOut, balOutExp) - - //Regular CheckTx - et.reset() - et.acc2State(et.accIn) - et.acc2State(et.accOut) - res, _, _, _, _ = et.exec(tx, true) - assert.True(res.IsOK(), "ExecTx/Good CheckTx: Expected OK return from ExecTx, Error: %v", res) - - // rige: go hack the cli and abuse this to steal some coinz.... I'm not fixing, but re-writing SendTx - //Negative CheckTx - // et.reset() - // et.acc2State(et.accIn) - // et.acc2State(et.accOut) - // tx2 := types.MakeSendTx(1, et.accOut, et.accIn) - // tx2.Fee = types.Coin{"mycoin", 0} - // tx2.Inputs[0].Coins = types.Coins{{"mycoin", -5}} - // tx2.Outputs[0].Coins = types.Coins{{"mycoin", -5}} - // et.signTx(tx2, et.accIn) - // res, _, _, _, _ = et.exec(tx2, true) - // assert.True(res.IsErr(), "ExecTx/Bad CheckTx: Expected error return from ExecTx, returned: %v", res) - - //Regular DeliverTx - et.reset() - et.acc2State(et.accIn) - et.acc2State(et.accOut) - res, balIn, balInExp, balOut, balOutExp = et.exec(tx, false) - assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res) - assert.True(balIn.IsEqual(balInExp), - "ExecTx/good DeliverTx: unexpected change in input balance, got: %v, expected: %v", balIn, balInExp) - assert.True(balOut.IsEqual(balOutExp), - "ExecTx/good DeliverTx: unexpected change in output balance, got: %v, expected: %v", balOut, balOutExp) -} - -func TestSendTxIBC(t *testing.T) { - assert := assert.New(t) - et := newExecTest() - - //ExecTx - chainID2 := "otherchain" - tx := types.MakeSendTx(1, et.accOut, et.accIn) - dstAddress := tx.Outputs[0].Address - tx.Outputs[0].Address = []byte(chainID2 + "/" + string(tx.Outputs[0].Address)) - et.acc2State(et.accIn) - et.signTx(tx, et.accIn) - - //Regular DeliverTx - et.reset() - et.acc2State(et.accIn) - - initBalIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance - - res := ExecTx(et.state, nil, tx, false, nil) - - balIn := et.state.GetAccount(et.accIn.Account.PubKey.Address()).Balance - decrBalInExp := tx.Outputs[0].Coins.Plus(types.Coins{tx.Fee}) //expected decrease in balance In - balInExp := initBalIn.Minus(decrBalInExp) - - assert.True(res.IsOK(), "ExecTx/Good DeliverTx: Expected OK return from ExecTx, Error: %v", res) - assert.True(balIn.IsEqual(balInExp), - "ExecTx/good DeliverTx: unexpected change in input balance, got: %v, expected: %v", balIn, balInExp) - - packet, err := ibc.GetIBCPacket(et.state, et.chainID, chainID2, 0) - assert.Nil(err) - - assert.Equal(packet.SrcChainID, et.chainID) - assert.Equal(packet.DstChainID, chainID2) - assert.Equal(packet.Sequence, uint64(0)) - assert.Equal(packet.Type, "coin") - - coins, ok := packet.Payload.(ibc.CoinsPayload) - assert.True(ok) - assert.Equal(coins.Coins, tx.Outputs[0].Coins) - assert.EqualValues(coins.Address, dstAddress) -} diff --git a/state/state.go b/state/state.go index da370da817..36b5114d2e 100644 --- a/state/state.go +++ b/state/state.go @@ -57,14 +57,6 @@ func (s *State) Set(key []byte, value []byte) { s.store.Set(key, value) } -func (s *State) GetAccount(addr []byte) *types.Account { - return types.GetAccount(s, addr) -} - -func (s *State) SetAccount(addr []byte, acc *types.Account) { - types.SetAccount(s, addr, acc) -} - func (s *State) CacheWrap() *State { cache := types.NewKVCache(s) return &State{ diff --git a/state/state_test.go b/state/state_test.go index 990659d361..4d3486c5b1 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -20,9 +20,6 @@ func TestState(t *testing.T) { cache := state.CacheWrap() eyesCli := eyes.NewLocalClient("", 0) - //Account and address for tests - dumAddr := []byte("dummyAddress") - acc := new(types.Account) acc.Sequence = 1 @@ -73,10 +70,6 @@ func TestState(t *testing.T) { setRecords(state) assert.True(storeHasAll(state), "state doesn't retrieve after Set") - // Test account retrieve - state.SetAccount(dumAddr, acc) - assert.Equal(state.GetAccount(dumAddr).Sequence, 1, "GetAccount not retrieving") - //Test CacheWrap with local mem store reset() setRecords(cache)