Moves PoW tag to the new style of tag builders.

This commit is contained in:
Vitor Pamplona 2025-01-15 10:10:10 -05:00
parent 4b52cdb101
commit b90aac496e
11 changed files with 159 additions and 25 deletions

View File

@ -162,7 +162,8 @@ import com.vitorpamplona.quartz.nip01Core.tags.geohash.getGeoHash
import com.vitorpamplona.quartz.nip04Dm.PrivateDmEvent
import com.vitorpamplona.quartz.nip10Notes.BaseTextNoteEvent
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
import com.vitorpamplona.quartz.nip13Pow.getPoWRank
import com.vitorpamplona.quartz.nip13Pow.pow
import com.vitorpamplona.quartz.nip13Pow.strongPoWOrNull
import com.vitorpamplona.quartz.nip17Dm.ChatMessageEncryptedFileHeaderEvent
import com.vitorpamplona.quartz.nip17Dm.ChatMessageEvent
import com.vitorpamplona.quartz.nip17Dm.ChatMessageRelayListEvent
@ -980,8 +981,8 @@ fun SecondUserInfoRow(
DisplayReward(baseReward, note, accountViewModel, nav)
}
val pow = remember(noteEvent) { noteEvent.getPoWRank() }
if (pow > 20) {
val pow = remember(noteEvent) { noteEvent.strongPoWOrNull() }
if (pow != null) {
Spacer(StdHorzSpacer)
DisplayPoW(pow)
}

View File

@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.note.elements
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import com.vitorpamplona.amethyst.ui.theme.Font14SP
@ -40,10 +39,8 @@ fun DisplayPoWPreview() {
@Composable
fun DisplayPoW(pow: Int) {
val powStr = remember(pow) { "PoW-$pow" }
Text(
powStr,
"PoW-$pow",
color = MaterialTheme.colorScheme.lessImportantLink,
fontSize = Font14SP,
fontWeight = FontWeight.Bold,

View File

@ -175,7 +175,8 @@ import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.tags.addressables.isTaggedAddressableKind
import com.vitorpamplona.quartz.nip01Core.tags.geohash.getGeoHash
import com.vitorpamplona.quartz.nip04Dm.PrivateDmEvent
import com.vitorpamplona.quartz.nip13Pow.getPoWRank
import com.vitorpamplona.quartz.nip13Pow.pow
import com.vitorpamplona.quartz.nip13Pow.strongPoWOrNull
import com.vitorpamplona.quartz.nip17Dm.ChatMessageRelayListEvent
import com.vitorpamplona.quartz.nip18Reposts.GenericRepostEvent
import com.vitorpamplona.quartz.nip18Reposts.RepostEvent
@ -478,8 +479,8 @@ private fun FullBleedNoteCompose(
DisplayReward(baseReward, baseNote, accountViewModel, nav)
}
val pow = remember { noteEvent.getPoWRank() }
if (pow > 20) {
val pow = remember(noteEvent) { noteEvent.strongPoWOrNull() }
if (pow != null) {
DisplayPoW(pow)
}

View File

@ -26,24 +26,24 @@ import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class PoWRankTest {
class PoWRankProcessorTest {
@Test
fun setPoW() {
assertEquals(26, PoWRank.get("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e"))
assertEquals(26, PoWRankProcessor.calculatePowRankOf("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e"))
}
@Test
fun setPoWIfCommited25() {
assertEquals(25, PoWRank.getCommited("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 25))
assertEquals(25, PoWRankProcessor.compute("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 25))
}
@Test
fun setPoWIfCommited26() {
assertEquals(26, PoWRank.getCommited("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 26))
assertEquals(26, PoWRankProcessor.compute("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 26))
}
@Test
fun setPoWIfCommited27() {
assertEquals(26, PoWRank.getCommited("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 27))
assertEquals(26, PoWRankProcessor.compute("00000026c91e9fc75fdb95b367776e2594b931cebda6d5ca3622501006669c9e", 27))
}
}

View File

@ -22,7 +22,7 @@ package com.vitorpamplona.quartz.experimental.limits
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relays.filters.Filter
import com.vitorpamplona.quartz.nip13Pow.getPoWRank
import com.vitorpamplona.quartz.nip13Pow.pow
import com.vitorpamplona.quartz.utils.TimeUtils
class LimitProcessor {
@ -77,7 +77,7 @@ class LimitProcessor {
if (!limits.acceptedEventKinds.isNullOrEmpty() && ev.kind !in limits.acceptedEventKinds) return false
if (!limits.blockedEventKinds.isNullOrEmpty() && ev.kind in limits.blockedEventKinds) return false
if (limits.minPoW != null && ev.getPoWRank() < limits.minPoW) return false
if (limits.minPoW != null && ev.pow() < limits.minPoW) return false
if (limits.maxEventTags != null && ev.tags.size > limits.maxEventTags) return false
if (limits.maxContentLength != null && ev.content.length > limits.maxContentLength) return false

View File

@ -22,7 +22,22 @@ package com.vitorpamplona.quartz.nip13Pow
import com.vitorpamplona.quartz.nip01Core.core.Event
fun Event.getPoWRank(): Int {
val commitedPoW = tags.firstOrNull { it.size > 2 && it[0] == "nonce" }?.get(2)?.toIntOrNull()
return PoWRank.getCommited(id, commitedPoW)
fun Event.pow() = PoWRankProcessor.compute(id, tags.commitedPoW())
fun Event.hasPoWTag() = tags.hasPoW()
/**
* Returns the Proof Or Work rank when commited if it is equal or stronger than the minimum.
*
* Performance-conscious method
*/
fun Event.strongPoWOrNull(min: Int = 20): Int? {
val commitment = tags.commitedPoW()
if (commitment != null) {
val pow = PoWRankProcessor.compute(id, commitment)
if (pow >= min) {
return pow
}
}
return null
}

View File

@ -20,13 +20,15 @@
*/
package com.vitorpamplona.quartz.nip13Pow
class PoWRank {
import com.vitorpamplona.quartz.nip01Core.HexKey
class PoWRankProcessor {
companion object {
fun getCommited(
id: String,
fun compute(
id: HexKey,
commitedPoW: Int?,
): Int {
val actualRank = get(id)
val actualRank = calculatePowRankOf(id)
return if (commitedPoW == null) {
actualRank
@ -39,7 +41,7 @@ class PoWRank {
}
}
fun get(id: String): Int {
fun calculatePowRankOf(id: HexKey): Int {
var rank = 0
for (i in 0..id.length) {
if (id[i] == '0') {

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip13Pow
import com.vitorpamplona.quartz.utils.arrayOfNotNull
import com.vitorpamplona.quartz.utils.bytesUsedInMemory
import com.vitorpamplona.quartz.utils.pointerSizeInBytes
class PoWTag(
val nonce: String,
val commitment: String?,
) {
fun countMemory(): Long = 2 * pointerSizeInBytes + nonce.bytesUsedInMemory() + (commitment?.bytesUsedInMemory() ?: 0)
fun toTagArray() = assemble(nonce, commitment)
companion object {
val TAG_NAME = "nonce"
@JvmStatic
fun parse(tags: Array<String>): PoWTag {
require(tags[0] == TAG_NAME)
return PoWTag(tags[1], tags.getOrNull(2))
}
@JvmStatic
fun assemble(
nonce: String,
commitment: String?,
) = arrayOfNotNull(TAG_NAME, nonce, commitment)
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip13Pow
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
fun TagArrayBuilder.pow(
nonce: String,
commitment: Int,
) = add(PoWTag.assemble(nonce, commitment.toString()))
fun TagArrayBuilder.pow(
nonce: String,
commitment: String,
) = add(PoWTag.assemble(nonce, commitment))
fun TagArrayBuilder.pow(tag: PoWTag) = add(tag.toTagArray())

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2024 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip13Pow
import com.vitorpamplona.quartz.nip01Core.core.TagArray
import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent
import com.vitorpamplona.quartz.nip01Core.core.mapTagged
fun TagArray.commitedPoW() = this.firstOrNull { it.size > 2 && it[0] == "nonce" }?.get(2)?.toIntOrNull()
fun TagArray.hasPoW() = this.hasTagWithContent(PoWTag.TAG_NAME)
fun TagArray.powTags() = this.mapTagged(PoWTag.TAG_NAME) { PoWTag.parse(it) }

View File

@ -20,6 +20,8 @@
*/
package com.vitorpamplona.quartz.utils
public fun arrayOfNotNull(vararg elements: String?) = removeTrailingNullsAndEmptyOthers(*elements)
public fun removeTrailingNullsAndEmptyOthers(vararg elements: String?): Array<String> {
val lastNonNullIndex = elements.indexOfLast { it != null }