dcSpark / cardano-multiplatform-lib

Rust implementation of Cardano
MIT License
98 stars 36 forks source link

Unexpected serialization of PoolRegistration cert #249

Closed AngelCastilloB closed 1 year ago

AngelCastilloB commented 1 year ago

The pool registration certificate is defined in the CDDL as:

pool_registration = (3, pool_params)

I would expect this to be serialized to something like: [ 03, [ pool param data ] ] (array of 2 elements with a nested array of 9 elements for pool params), or in CBOR:

82                                      # array(2)
   03                                   # unsigned(3)
   89                                   # array(9)
      58 1C                             # bytes(28)
         D85087C646951407198C27B1B950FD2E99F28586C000CE39F6E6EF92 # "\xD8P\x87\xC6F\x95\u0014\a\u0019\x8C'\xB1\xB9P\xFD.\x99\xF2\x85\x86\xC0\u0000\xCE9\xF6\xE6\xEF\x92"
      58 20                             # bytes(32)
         8DD154228946BD12967C12BEDB1CB6038B78F8B84A1760B1A788FA72A4AF3DB0 # "\x8D\xD1T\"\x89F\xBD\u0012\x96|\u0012\xBE\xDB\u001C\xB6\u0003\x8Bx\xF8\xB8J\u0017`\xB1\xA7\x88\xFAr\xA4\xAF=\xB0"
      19 2710                           # unsigned(10000)
      19 03E8                           # unsigned(1000)
      D8 1E                             # tag(30)
         82                             # array(2)
            01                          # unsigned(1)
            05                          # unsigned(5)
      58 1D                             # bytes(29)
         E1CB0EC2692497B458E46812C8A5BFA2931D1A2D965A99893828EC810F # "\xE1\xCB\u000E\xC2i$\x97\xB4X\xE4h\u0012ȥ\xBF\xA2\x93\u001D\u001A-\x96Z\x99\x898(\xEC\x81\u000F"
      81                                # array(1)
         58 1C                          # bytes(28)
            CB0EC2692497B458E46812C8A5BFA2931D1A2D965A99893828EC810F # "\xCB\u000E\xC2i$\x97\xB4X\xE4h\u0012ȥ\xBF\xA2\x93\u001D\u001A-\x96Z\x99\x898(\xEC\x81\u000F"
      83                                # array(3)
         83                             # array(3)
            01                          # unsigned(1)
            19 1388                     # unsigned(5000)
            6B                          # text(11)
               6578616D706C652E636F6D   # "example.com"
         84                             # array(4)
            00                          # unsigned(0)
            19 1770                     # unsigned(6000)
            44                          # bytes(4)
               7F000001                 # "\u0000\u0000\u0001"
            F6                          # primitive(22)
         82                             # array(2)
            02                          # unsigned(2)
            6B                          # text(11)
               6578616D706C652E636F6D   # "example.com"
      82                                # array(2)
         73                             # text(19)
            68747470733A2F2F6578616D706C652E636F6D # "https://example.com"
         58 20                          # bytes(32)
            0F3ABBC8FC19C2E61BAB6059BF8A466E6E754833A08A62A6C56FE0E78F19D9D5 # "\u000F:\xBB\xC8\xFC\u0019\xC2\xE6\e\xAB`Y\xBF\x8AFnnuH3\xA0\x8Ab\xA6\xC5o\xE0\xE7\x8F\u0019\xD9\xD5"

However the CML is serializing this certificate as [ 03 + pool param data] (single flat array of 10 elements), or in CBOR:

8A                                      # array(10)
   03                                   # unsigned(3)
   58 1C                                # bytes(28)
      D85087C646951407198C27B1B950FD2E99F28586C000CE39F6E6EF92 # "\xD8P\x87\xC6F\x95\u0014\a\u0019\x8C'\xB1\xB9P\xFD.\x99\xF2\x85\x86\xC0\u0000\xCE9\xF6\xE6\xEF\x92"
   58 20                                # bytes(32)
      8DD154228946BD12967C12BEDB1CB6038B78F8B84A1760B1A788FA72A4AF3DB0 # "\x8D\xD1T\"\x89F\xBD\u0012\x96|\u0012\xBE\xDB\u001C\xB6\u0003\x8Bx\xF8\xB8J\u0017`\xB1\xA7\x88\xFAr\xA4\xAF=\xB0"
   19 2710                              # unsigned(10000)
   19 03E8                              # unsigned(1000)
   D8 1E                                # tag(30)
      82                                # array(2)
         01                             # unsigned(1)
         05                             # unsigned(5)
   58 1D                                # bytes(29)
      E1CB0EC2692497B458E46812C8A5BFA2931D1A2D965A99893828EC810F # "\xE1\xCB\u000E\xC2i$\x97\xB4X\xE4h\u0012ȥ\xBF\xA2\x93\u001D\u001A-\x96Z\x99\x898(\xEC\x81\u000F"
   81                                   # array(1)
      58 1C                             # bytes(28)
         CB0EC2692497B458E46812C8A5BFA2931D1A2D965A99893828EC810F # "\xCB\u000E\xC2i$\x97\xB4X\xE4h\u0012ȥ\xBF\xA2\x93\u001D\u001A-\x96Z\x99\x898(\xEC\x81\u000F"
   83                                   # array(3)
      83                                # array(3)
         01                             # unsigned(1)
         19 1388                        # unsigned(5000)
         6B                             # text(11)
            6578616D706C652E636F6D      # "example.com"
      84                                # array(4)
         00                             # unsigned(0)
         19 1770                        # unsigned(6000)
         44                             # bytes(4)
            7F000001                    # "\u0000\u0000\u0001"
         F6                             # primitive(22)
      82                                # array(2)
         02                             # unsigned(2)
         6B                             # text(11)
            6578616D706C652E636F6D      # "example.com"
   82                                   # array(2)
      73                                # text(19)
         68747470733A2F2F6578616D706C652E636F6D # "https://example.com"
      58 20                             # bytes(32)
         0F3ABBC8FC19C2E61BAB6059BF8A466E6E754833A08A62A6C56FE0E78F19D9D5 # "\u000F:\xBB\xC8\xFC\u0019\xC2\xE6\e\xAB`Y\xBF\x8AFnnuH3\xA0\x8Ab\xA6\xC5o\xE0\xE7\x8F\u0019\xD9\xD5"

This is different that how the other structures are serialized, in which each sub structure is encoded as is as a single entry in the parent array, is there any reason why this particular case is different?

rooooooooob commented 1 year ago

@AngelCastilloB notice how pool_params is defined:

pool_params = ( operator:       pool_keyhash
              , vrf_keyhash:    vrf_keyhash
              , pledge:         coin
              , cost:           coin
              , margin:         unit_interval
              , reward_account: reward_account
              , pool_owners:    set<addr_keyhash>
              , relays:         [* relay]
              , pool_metadata:  pool_metadata / null
              )

pool_params is a basic group (it is NOT encoded as an array - notice the ( and ) not [ and ]) which means the fields will be inserted into pool_registration.

AngelCastilloB commented 1 year ago

Hi @rooooooooob I see now, thanks for the information and the quick reply!.

rooooooooob commented 1 year ago

If you want more info about basic groups and the behavior check out section 2.1 of the CDDL RFC (groups and composition). Keep in mind in babbage.cddl (and ONLY in babbage - previous eras seem to correctly follow the basic group insertion for operational certs/versions) we seem to have the babbage.cddl spec possibly incorrect regarding basic groups (input-output-hk/cardano-ledger#3559). The currently published CML hasn't been updated regarding this but the next version should have that fix (#246). It's only an issue if you're working with babbage blocks/block headers though.

AngelCastilloB commented 1 year ago

This is really useful @rooooooooob thanks