diff --git a/lib/flutter_libsparkmobile.dart b/lib/flutter_libsparkmobile.dart index 304bee6e..2f20bb36 100644 --- a/lib/flutter_libsparkmobile.dart +++ b/lib/flutter_libsparkmobile.dart @@ -20,8 +20,8 @@ const kSparkBaseDerivationPath = "m/44'/136'/0'/$kSparkChain/"; const kSparkBaseDerivationPathTestnet = "m/44'/1'/0'/$kSparkChain/"; const kMaxNameLength = - 20; // max 20 symbols, alphanumerical or "-_.", case-insensitive -const kNameRegexString = r'^[a-zA-Z0-9\-_\.]+$'; + 20; // max 20 symbols, alphanumerical or "-.", case-insensitive +const kNameRegexString = r'^[a-zA-Z0-9.-]+$'; const kMaxAdditionalInfoLengthBytes = 1024; const kMaxNameRegistrationLengthYears = 10; const kStage3CommunityFundAddressMainNet = "aFA2TbqG9cnhhzX5Yny2pBJRK5EaEqLCH7"; diff --git a/src/deps/sparkmobile/src/sparkname.h b/src/deps/sparkmobile/src/sparkname.h index 0d2805f8..a9a77716 100644 --- a/src/deps/sparkmobile/src/sparkname.h +++ b/src/deps/sparkmobile/src/sparkname.h @@ -9,7 +9,7 @@ namespace spark { struct CSparkNameTxData { public: - static const uint16_t CURRENT_VERSION = 1; + static const uint16_t CURRENT_VERSION = 2; public: uint16_t nVersion{CURRENT_VERSION}; // version @@ -27,6 +27,8 @@ struct CSparkNameTxData std::string additionalInfo; // failsafe if the hash of the transaction data is can't be converted to a scalar for proof creation/verification uint32_t hashFailsafe{0}; + // Registration-only; add transfer fields if mobile starts creating Spark Name transfers. + uint8_t operationType{0}; ADD_SERIALIZE_METHODS; @@ -34,6 +36,8 @@ struct CSparkNameTxData void SerializationOp(Stream &s, Operation ser_action) { READWRITE(nVersion); + if (nVersion != 1 && nVersion != 2) + throw std::ios_base::failure("Unsupported Spark Name transaction data version"); READWRITE(inputsHash); READWRITE(name); READWRITE(sparkAddress); @@ -41,6 +45,10 @@ struct CSparkNameTxData READWRITE(sparkNameValidityBlocks); READWRITE(additionalInfo); READWRITE(hashFailsafe); + if (nVersion == 2) + { + READWRITE(operationType); + } } }; diff --git a/src/deps/sparkmobile/tests/spark_name_test.cpp b/src/deps/sparkmobile/tests/spark_name_test.cpp index 018e70c0..302b909e 100644 --- a/src/deps/sparkmobile/tests/spark_name_test.cpp +++ b/src/deps/sparkmobile/tests/spark_name_test.cpp @@ -42,6 +42,8 @@ BOOST_AUTO_TEST_CASE(spark_names) BOOST_CHECK_EQUAL(decodedData.sparkAddress, sparkNameData.sparkAddress); BOOST_CHECK_EQUAL(decodedData.sparkNameValidityBlocks, sparkNameData.sparkNameValidityBlocks); BOOST_CHECK_EQUAL(decodedData.additionalInfo, sparkNameData.additionalInfo); + BOOST_CHECK_EQUAL(decodedData.nVersion, uint16_t{2}); + BOOST_CHECK_EQUAL((int)decodedData.operationType, 0); BOOST_CHECK(!decodedData.addressOwnershipProof.empty()); spark::OwnershipProof deserializedOwnershipProof; @@ -54,4 +56,19 @@ BOOST_AUTO_TEST_CASE(spark_names) BOOST_CHECK(address.verify_own(m, deserializedOwnershipProof)); } +BOOST_AUTO_TEST_CASE(rejects_unsupported_spark_name_versions) +{ + spark::CSparkNameTxData data; + data.nVersion = 3; + CDataStream serialized(SER_NETWORK, PROTOCOL_VERSION); + BOOST_CHECK_THROW(serialized << data, std::ios_base::failure); + + data.nVersion = 2; + CDataStream encodedData(SER_NETWORK, PROTOCOL_VERSION); + encodedData << data; + encodedData[0] = 3; + encodedData[1] = 0; + BOOST_CHECK_THROW(encodedData >> data, std::ios_base::failure); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/test/flutter_libsparkmobile_test.dart b/test/flutter_libsparkmobile_test.dart index 66dc9255..c3938118 100644 --- a/test/flutter_libsparkmobile_test.dart +++ b/test/flutter_libsparkmobile_test.dart @@ -3,6 +3,12 @@ import 'package:flutter_libsparkmobile/src/extensions.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + test('Spark Names reject underscores', () { + final pattern = RegExp(kNameRegexString); + expect(pattern.hasMatch('NAME-FOR.TESTING'), isTrue); + expect(pattern.hasMatch('NAME_FOR_TESTING'), isFalse); + }); + test('mnemonic to address test', () async { // Generate key data from the mnemonic. //