package gossip import ( "bytes" "strconv" "github.com/iotaledger/goshimmer/packages/accountability" "github.com/iotaledger/goshimmer/packages/byteutils" "github.com/iotaledger/goshimmer/packages/errors" "github.com/iotaledger/goshimmer/packages/events" "github.com/iotaledger/goshimmer/packages/identity" "github.com/iotaledger/goshimmer/packages/model/meta_transaction" "github.com/iotaledger/goshimmer/packages/ternary" ) // region protocolV1 /////////////////////////////////////////////////////////////////////////////////////////////////// func protocolV1(protocol *protocol) errors.IdentifiableError { if err := protocol.Send(accountability.OwnId()); err != nil { return err } onReceiveIdentification := events.NewClosure(func(identity *identity.Identity) { if protocol.Neighbor == nil { if err := protocol.Send(CONNECTION_REJECT); err != nil { return } } else { if err := protocol.Send(CONNECTION_ACCEPT); err != nil { return } protocol.handshakeMutex.Lock() defer protocol.handshakeMutex.Unlock() protocol.sendHandshakeCompleted = true if protocol.receiveHandshakeCompleted { protocol.Events.HandshakeCompleted.Trigger() } } }) protocol.Events.ReceiveIdentification.Attach(onReceiveIdentification) return nil } func sendTransactionV1(protocol *protocol, tx *meta_transaction.MetaTransaction) { if _, ok := protocol.SendState.(*dispatchStateV1); ok { protocol.sendMutex.Lock() defer protocol.sendMutex.Unlock() if err := protocol.send(DISPATCH_TRANSACTION); err != nil { return } if err := protocol.send(tx); err != nil { return } } } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region indentificationStateV1 /////////////////////////////////////////////////////////////////////////////////////// type indentificationStateV1 struct { protocol *protocol buffer []byte offset int } func newIndentificationStateV1(protocol *protocol) *indentificationStateV1 { return &indentificationStateV1{ protocol: protocol, buffer: make([]byte, MARSHALLED_IDENTITY_TOTAL_SIZE), offset: 0, } } func (state *indentificationStateV1) Receive(data []byte, offset int, length int) (int, errors.IdentifiableError) { bytesRead := byteutils.ReadAvailableBytesToBuffer(state.buffer, state.offset, data, offset, length) state.offset += bytesRead if state.offset == MARSHALLED_IDENTITY_TOTAL_SIZE { if receivedIdentity, err := unmarshalIdentity(state.buffer); err != nil { return bytesRead, ErrInvalidAuthenticationMessage.Derive(err, "invalid authentication message") } else { protocol := state.protocol if neighbor, exists := GetNeighbor(receivedIdentity.StringIdentifier); exists { protocol.Neighbor = neighbor } else { protocol.Neighbor = nil } protocol.Events.ReceiveIdentification.Trigger(receivedIdentity) protocol.ReceivingState = newacceptanceStateV1(protocol) state.offset = 0 } } return bytesRead, nil } func (state *indentificationStateV1) Send(param interface{}) errors.IdentifiableError { if id, ok := param.(*identity.Identity); ok { if signature, err := id.Sign(id.Identifier); err == nil { protocol := state.protocol if _, err := protocol.Conn.Write(id.Identifier); err != nil { return ErrSendFailed.Derive(err, "failed to send identifier") } if _, err := protocol.Conn.Write(signature); err != nil { return ErrSendFailed.Derive(err, "failed to send signature") } protocol.SendState = newacceptanceStateV1(protocol) return nil } } return ErrInvalidSendParam.Derive("passed in parameter is not a valid identity") } func unmarshalIdentity(data []byte) (*identity.Identity, error) { identifier := data[MARSHALLED_IDENTITY_START:MARSHALLED_IDENTITY_END] if restoredIdentity, err := identity.FromSignedData(identifier, data[MARSHALLED_IDENTITY_SIGNATURE_START:MARSHALLED_IDENTITY_SIGNATURE_END]); err != nil { return nil, err } else { if bytes.Equal(identifier, restoredIdentity.Identifier) { return restoredIdentity, nil } else { return nil, errors.New("signature does not match claimed identity") } } } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region acceptanceStateV1 //////////////////////////////////////////////////////////////////////////////////////////// type acceptanceStateV1 struct { protocol *protocol } func newacceptanceStateV1(protocol *protocol) *acceptanceStateV1 { return &acceptanceStateV1{protocol: protocol} } func (state *acceptanceStateV1) Receive(data []byte, offset int, length int) (int, errors.IdentifiableError) { protocol := state.protocol switch data[offset] { case 0: protocol.Events.ReceiveConnectionRejected.Trigger() _ = protocol.Conn.Close() protocol.ReceivingState = nil case 1: protocol.Events.ReceiveConnectionAccepted.Trigger() protocol.ReceivingState = newDispatchStateV1(protocol) default: return 1, ErrInvalidStateTransition.Derive("invalid acceptance state transition (" + strconv.Itoa(int(data[offset])) + ")") } return 1, nil } func (state *acceptanceStateV1) Send(param interface{}) errors.IdentifiableError { if responseType, ok := param.(byte); ok { switch responseType { case CONNECTION_REJECT: protocol := state.protocol if _, err := protocol.Conn.Write([]byte{CONNECTION_REJECT}); err != nil { return ErrSendFailed.Derive(err, "failed to send reject message") } _ = protocol.Conn.Close() protocol.SendState = nil return nil case CONNECTION_ACCEPT: protocol := state.protocol if _, err := protocol.Conn.Write([]byte{CONNECTION_ACCEPT}); err != nil { return ErrSendFailed.Derive(err, "failed to send accept message") } protocol.SendState = newDispatchStateV1(protocol) return nil } } return ErrInvalidSendParam.Derive("passed in parameter is not a valid acceptance byte") } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region dispatchStateV1 ////////////////////////////////////////////////////////////////////////////////////////////// type dispatchStateV1 struct { protocol *protocol } func newDispatchStateV1(protocol *protocol) *dispatchStateV1 { return &dispatchStateV1{ protocol: protocol, } } func (state *dispatchStateV1) Receive(data []byte, offset int, length int) (int, errors.IdentifiableError) { switch data[0] { case DISPATCH_DROP: protocol := state.protocol protocol.Events.ReceiveConnectionRejected.Trigger() _ = protocol.Conn.Close() protocol.ReceivingState = nil case DISPATCH_TRANSACTION: protocol := state.protocol protocol.ReceivingState = newTransactionStateV1(protocol) case DISPATCH_REQUEST: protocol := state.protocol protocol.ReceivingState = newRequestStateV1(protocol) default: return 1, ErrInvalidStateTransition.Derive("invalid dispatch state transition (" + strconv.Itoa(int(data[offset])) + ")") } return 1, nil } func (state *dispatchStateV1) Send(param interface{}) errors.IdentifiableError { if dispatchByte, ok := param.(byte); ok { switch dispatchByte { case DISPATCH_DROP: protocol := state.protocol if _, err := protocol.Conn.Write([]byte{DISPATCH_DROP}); err != nil { return ErrSendFailed.Derive(err, "failed to send drop message") } _ = protocol.Conn.Close() protocol.SendState = nil return nil case DISPATCH_TRANSACTION: protocol := state.protocol if _, err := protocol.Conn.Write([]byte{DISPATCH_TRANSACTION}); err != nil { return ErrSendFailed.Derive(err, "failed to send transaction dispatch byte") } protocol.SendState = newTransactionStateV1(protocol) return nil case DISPATCH_REQUEST: protocol := state.protocol if _, err := protocol.Conn.Write([]byte{DISPATCH_REQUEST}); err != nil { return ErrSendFailed.Derive(err, "failed to send request dispatch byte") } protocol.SendState = newTransactionStateV1(protocol) return nil } } return ErrInvalidSendParam.Derive("passed in parameter is not a valid dispatch byte") } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region transactionStateV1 /////////////////////////////////////////////////////////////////////////////////////////// type transactionStateV1 struct { protocol *protocol buffer []byte offset int } func newTransactionStateV1(protocol *protocol) *transactionStateV1 { return &transactionStateV1{ protocol: protocol, buffer: make([]byte, meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE), offset: 0, } } func (state *transactionStateV1) Receive(data []byte, offset int, length int) (int, errors.IdentifiableError) { bytesRead := byteutils.ReadAvailableBytesToBuffer(state.buffer, state.offset, data, offset, length) state.offset += bytesRead if state.offset == meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE { protocol := state.protocol transactionData := make([]byte, meta_transaction.MARSHALLED_TOTAL_SIZE/ternary.NUMBER_OF_TRITS_IN_A_BYTE) copy(transactionData, state.buffer) protocol.Events.ReceiveTransactionData.Trigger(transactionData) go ProcessReceivedTransactionData(transactionData) protocol.ReceivingState = newDispatchStateV1(protocol) state.offset = 0 } return bytesRead, nil } func (state *transactionStateV1) Send(param interface{}) errors.IdentifiableError { if tx, ok := param.(*meta_transaction.MetaTransaction); ok { protocol := state.protocol if _, err := protocol.Conn.Write(tx.GetBytes()); err != nil { return ErrSendFailed.Derive(err, "failed to send transaction") } protocol.SendState = newDispatchStateV1(protocol) return nil } return ErrInvalidSendParam.Derive("passed in parameter is not a valid transaction") } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region requestStateV1 /////////////////////////////////////////////////////////////////////////////////////////////// type requestStateV1 struct { buffer []byte offset int } func newRequestStateV1(protocol *protocol) *requestStateV1 { return &requestStateV1{ buffer: make([]byte, 1), offset: 0, } } func (state *requestStateV1) Receive(data []byte, offset int, length int) (int, errors.IdentifiableError) { return 0, nil } func (state *requestStateV1) Send(param interface{}) errors.IdentifiableError { return nil } // endregion /////////////////////////////////////////////////////////////////////////////////////////////////////////// // region constants and variables ////////////////////////////////////////////////////////////////////////////////////// const ( VERSION_1 = byte(1) CONNECTION_REJECT = byte(0) CONNECTION_ACCEPT = byte(1) DISPATCH_DROP = byte(0) DISPATCH_TRANSACTION = byte(1) DISPATCH_REQUEST = byte(2) MARSHALLED_IDENTITY_START = 0 MARSHALLED_IDENTITY_SIGNATURE_START = MARSHALLED_IDENTITY_END MARSHALLED_IDENTITY_SIZE = 20 MARSHALLED_IDENTITY_SIGNATURE_SIZE = 65 MARSHALLED_IDENTITY_END = MARSHALLED_IDENTITY_START + MARSHALLED_IDENTITY_SIZE MARSHALLED_IDENTITY_SIGNATURE_END = MARSHALLED_IDENTITY_SIGNATURE_START + MARSHALLED_IDENTITY_SIGNATURE_SIZE MARSHALLED_IDENTITY_TOTAL_SIZE = MARSHALLED_IDENTITY_SIGNATURE_END ) // endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////