package transport import ( "encoding/binary" "net" "ripple/crypto" "ripple/state" "ripple/types" "ripple/udpr" ) type AccountTransport struct { d *state.State m *AccountSenderManager } type sendRequest struct { data []byte dest *net.UDPAddr } func NewAccountTransport(conn *udpr.UDPRConn, st *state.State) (*AccountTransport, *AccountSenderManager) { t := &AccountTransport{d: st} t.m = newAccountSenderManager(conn) return t, t.m } func (t *AccountTransport) Receive(tx []byte, addr *net.UDPAddr) (types.Transaction, error) { if len(tx) < 1+32+64+4+1+32 { return types.Transaction{}, errInvalidTransaction } id := parseTxFrom(tx) acc, ok := t.d.Storage.Accounts[id] if !ok { return types.Transaction{}, errInvalidTransaction } if !crypto.VerifySignature(tx, acc.SecretKey) { return types.Transaction{}, errInvalidTransaction } counter := binary.BigEndian.Uint32(tx[97:101]) if counter <= acc.CounterIn { return types.Transaction{}, errInvalidTransaction } t.d.MustSetCounterIn(id, counter) command := tx[101] args := tx[102:len(tx)-32] return types.Transaction{ Identifier: id, Instruction: types.Instruction{Command: command, Arguments: args}, }, nil } func (t *AccountTransport) Send(id types.UserIdentifier, instr types.Instruction) { counter, err := t.d.IncrementAndGetCounterOut(id) if err != nil { return } raw := buildTx( accountType, id.Username, t.d.Storage.User.UserIdentifier, counter, instr, ) acc, ok := t.d.Storage.Accounts[id] if !ok { return } signed := crypto.SignData(raw, acc.SecretKey) addr, err := getAddr(id.ServerAddress, acc.Port) if err != nil { return } t.m.enqueue(id, sendRequest{ data: signed, dest: addr, }) }