@@ -772,5 +772,143 @@ func TestSphinxHopVariableSizedPayloads(t *testing.T) {
772772 }
773773 }
774774}
775+
776+ // testFileName is the name of the multi-frame onion test file.
777+ const testFileName = "testdata/onion-test-multi-frame.json"
778+
779+ type jsonHop struct {
780+ Type string `json:"type"`
781+
782+ Pubkey string `json:"pubkey"`
783+
784+ Payload string `json:"payload"`
785+ }
786+
787+ type payloadTestCase struct {
788+ SessionKey string `json:"session_key"`
789+
790+ AssociatedData string `json:"associated_data"`
791+
792+ Hops []jsonHop `json:"hops"`
793+ }
794+
795+ type jsonTestCase struct {
796+ Comment string `json:"comment"`
797+
798+ Generate payloadTestCase `json:"generate"`
799+
800+ Onion string `json:"onion"`
801+
802+ Decode []string `json:"decode"`
803+ }
804+
805+ // jsonTypeToPayloadType maps the JSON payload type to our concrete PayloadType
806+ // type.
807+ func jsonTypeToPayloadType (jsonType string ) PayloadType {
808+ switch jsonType {
809+ case "raw" :
810+ fallthrough
811+ case "tlv" :
812+ return PayloadTLV
813+
814+ case "legacy" :
815+ return PayloadLegacy
816+
817+ default :
818+ panic (fmt .Sprintf ("unknown payload type: %v" , jsonType ))
819+ }
820+ }
821+
822+ // TestVariablePayloadOnion tests that if we construct a packet that contains a
823+ // mix of the old and new payload format, that we match the version that's
824+ // included in the spec.
825+ func TestVariablePayloadOnion (t * testing.T ) {
826+ t .Parallel ()
827+
828+ // First, we'll read out the raw JSOn file at the target location.
829+ jsonBytes , err := ioutil .ReadFile (testFileName )
830+ if err != nil {
831+ t .Fatalf ("unable to read json file: %v" , err )
832+ }
833+
834+ // Once we have the raw file, we'll unpack it into our jsonTestCase
835+ // struct defined above.
836+ testCase := & jsonTestCase {}
837+ if err := json .Unmarshal (jsonBytes , testCase ); err != nil {
838+ t .Fatalf ("unable to parse spec json file: %v" , err )
839+ }
840+
841+ // Next, we'll populate a new OnionHop using the information included
842+ // in this test case.
843+ var route PaymentPath
844+ for i , hop := range testCase .Generate .Hops {
845+ pubKeyBytes , err := hex .DecodeString (hop .Pubkey )
846+ if err != nil {
847+ t .Fatalf ("unable to decode pubkey: %v" , err )
848+ }
849+ pubKey , err := btcec .ParsePubKey (pubKeyBytes , btcec .S256 ())
850+ if err != nil {
851+ t .Fatalf ("unable to parse BOLT 4 pubkey #%d: %v" , i , err )
852+ }
853+
854+ payload , err := hex .DecodeString (hop .Payload )
855+ if err != nil {
856+ t .Fatalf ("unable to decode payload: %v" , err )
857+ }
858+
859+ payloadType := jsonTypeToPayloadType (hop .Type )
860+ route [i ] = OnionHop {
861+ NodePub : * pubKey ,
862+ HopPayload : HopPayload {
863+ Type : payloadType ,
864+ Payload : payload ,
865+ },
866+ }
867+
868+ if payloadType == PayloadLegacy {
869+ route [i ].HopPayload .Payload = append (
870+ []byte {0x00 }, route [i ].HopPayload .Payload ... ,
871+ )
872+
873+ route [i ].HopPayload .Payload = append (
874+ route [i ].HopPayload .Payload ,
875+ bytes .Repeat ([]byte {0x00 }, NumPaddingBytes )... ,
876+ )
877+ }
878+ }
879+
880+ finalPacket , err := hex .DecodeString (testCase .Onion )
881+ if err != nil {
882+ t .Fatalf ("unable to decode packet: %v" , err )
883+ }
884+
885+ sessionKeyBytes , err := hex .DecodeString (testCase .Generate .SessionKey )
886+ if err != nil {
887+ t .Fatalf ("unable to generate session key: %v" , err )
888+ }
889+
890+ associatedData , err := hex .DecodeString (testCase .Generate .AssociatedData )
891+ if err != nil {
892+ t .Fatalf ("unable to decode AD: %v" , err )
893+ }
894+
895+ // With all the required data assembled, we'll craft a new packet.
896+ sessionKey , _ := btcec .PrivKeyFromBytes (btcec .S256 (), sessionKeyBytes )
897+ pkt , err := NewOnionPacket (& route , sessionKey , associatedData )
898+ if err != nil {
899+ t .Fatalf ("unable to construct onion packet: %v" , err )
900+ }
901+
902+ var b bytes.Buffer
903+ if err := pkt .Encode (& b ); err != nil {
904+ t .Fatalf ("unable to decode onion packet: %v" , err )
905+ }
906+
907+ // Finally, we expect that our packet matches the packet included in
908+ // the spec's test vectors.
909+ if bytes .Compare (b .Bytes (), finalPacket ) != 0 {
910+ t .Fatalf ("final packet does not match expected BOLT 4 packet, " +
911+ "want: %s, got %s" , hex .EncodeToString (finalPacket ),
912+ hex .EncodeToString (b .Bytes ()))
775913 }
776914}
0 commit comments