-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wrapping current gas estimators with fetchable gas pricing (#25)
* Break out logic for gas estimations into lambda parameters. * Associate legacy naming for parameters to newer lambdas. * Add floating gas price fetching * Remove `fromSimulation()`, logic moved into cosmosSimulation estimator.
- Loading branch information
Showing
14 changed files
with
248 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
kotlin.code.style=official |
6 changes: 6 additions & 0 deletions
6
src/main/kotlin/io/provenance/client/TestnetFeaturePreview.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package io.provenance.client | ||
|
||
@RequiresOptIn(message = "This API is experimental and only exists in test.") | ||
@Retention(AnnotationRetention.BINARY) | ||
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) | ||
annotation class TestnetFeaturePreview |
26 changes: 26 additions & 0 deletions
26
src/main/kotlin/io/provenance/client/gas/estimators/CosmosSimulation.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package io.provenance.client.gas.estimators | ||
|
||
import cosmos.tx.v1beta1.ServiceOuterClass | ||
import io.provenance.client.gas.prices.GasPrices | ||
import io.provenance.client.grpc.GasEstimate | ||
import io.provenance.client.grpc.PbGasEstimator | ||
import io.provenance.client.internal.extensions.toCoin | ||
import kotlin.math.ceil | ||
|
||
/** | ||
* Cosmos simulation gas estimation. Must be used when interacting with pbc 1.7 or lower. | ||
* TODO - Remove once mainnet.version > 1.8 | ||
*/ | ||
internal fun cosmosSimulationGasEstimator(gasPrices: GasPrices): PbGasEstimator = { | ||
{ tx, adjustment -> | ||
val price = gasPrices() | ||
val sim = cosmosService.simulate( | ||
ServiceOuterClass.SimulateRequest.newBuilder() | ||
.setTxBytes(tx.toByteString()) | ||
.build() | ||
) | ||
val limit = ceil(sim.gasInfo.gasUsed * adjustment).toLong() | ||
val feeAmount = ceil(limit * price.amount.toDouble()).toLong() | ||
GasEstimate(limit, listOf(feeAmount.toCoin(price.denom))) | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/kotlin/io/provenance/client/gas/estimators/Floating.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.provenance.client.gas.estimators | ||
|
||
// import io.provenance.client.TestnetFeaturePreview | ||
import io.provenance.client.gas.prices.GasPrices | ||
import io.provenance.client.grpc.PbGasEstimator | ||
import io.provenance.client.internal.extensions.times | ||
|
||
// @TestnetFeaturePreview | ||
internal fun floatingGasPriceGasEstimator(delegate: PbGasEstimator, floatingGasPrice: GasPrices): PbGasEstimator = { | ||
{ tx, adjustment -> | ||
val price = floatingGasPrice() | ||
require(price.denom == "nhash") { "only nhash is supported for fees" } | ||
|
||
// Original estimate | ||
val estimate = delegate(this)(tx, adjustment) | ||
// Adjust up or down based on floating factor. | ||
val factor = price.amount.toDouble() / nodeGasPrice.value | ||
// Updated values | ||
estimate.copy(feesCalculated = estimate.feesCalculated * factor) | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/kotlin/io/provenance/client/gas/estimators/MsgFees.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package io.provenance.client.gas.estimators | ||
|
||
import io.provenance.client.grpc.GasEstimate | ||
import io.provenance.client.grpc.PbGasEstimator | ||
import io.provenance.msgfees.v1.CalculateTxFeesRequest | ||
|
||
/** | ||
* Message fee endpoint gas estimation. Only compatible and should be used with pbc 1.8 or greater. | ||
*/ | ||
// @TestnetFeaturePreview | ||
internal val MsgFeeCalculationGasEstimator: PbGasEstimator = { | ||
{ tx, adjustment -> | ||
val estimate = msgFeeClient.calculateTxFees( | ||
CalculateTxFeesRequest.newBuilder() | ||
.setTxBytes(tx.toByteString()) | ||
.setGasAdjustment(adjustment.toFloat()) | ||
.build() | ||
) | ||
GasEstimate(estimate.estimatedGas, estimate.totalFeesList) | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/main/kotlin/io/provenance/client/gas/prices/CachedGasPrice.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.provenance.client.gas.prices | ||
|
||
import cosmos.base.v1beta1.CoinOuterClass | ||
import io.provenance.client.internal.extensions.toCoin | ||
import java.time.OffsetDateTime | ||
import java.time.temporal.ChronoUnit | ||
import java.util.concurrent.atomic.AtomicReference | ||
import kotlin.time.Duration | ||
|
||
/** | ||
* Cache the gas prices for a determined period of time | ||
*/ | ||
class CachedGasPrice(private val gasPrices: GasPrices, private val duration: Duration) : GasPrices { | ||
private val lastFetch = AtomicReference(OffsetDateTime.MIN) | ||
private val cachedValue = AtomicReference("0nhash".toCoin()) | ||
|
||
override fun invoke(): CoinOuterClass.Coin { | ||
if (OffsetDateTime.now().isAfter(lastFetch.get().plus(duration.inWholeMilliseconds, ChronoUnit.MILLIS))) { | ||
cachedValue.set(gasPrices()) | ||
lastFetch.set(OffsetDateTime.now()) | ||
} | ||
return cachedValue.get() | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/kotlin/io/provenance/client/gas/prices/ConstantGasPrice.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package io.provenance.client.gas.prices | ||
|
||
import cosmos.base.v1beta1.CoinOuterClass | ||
|
||
class ConstantGasPrice(private val gasPrice: CoinOuterClass.Coin) : GasPrices { | ||
override fun invoke(): CoinOuterClass.Coin = gasPrice | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package io.provenance.client.gas.prices | ||
|
||
import cosmos.base.v1beta1.CoinOuterClass | ||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.hours | ||
|
||
typealias GasPrices = () -> CoinOuterClass.Coin | ||
|
||
fun GasPrices.cached(ttl: Duration = 1.hours): GasPrices = CachedGasPrice(this, ttl) |
35 changes: 35 additions & 0 deletions
35
src/main/kotlin/io/provenance/client/gas/prices/UrlGasPrices.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package io.provenance.client.gas.prices | ||
|
||
import com.google.gson.Gson | ||
import cosmos.base.v1beta1.CoinOuterClass | ||
import org.apache.http.client.methods.HttpGet | ||
import org.apache.http.impl.client.HttpClientBuilder | ||
import java.io.InputStreamReader | ||
|
||
/** | ||
* When provided with a url, fetches an object of shape '{"gasPrice":nnn,"gasPriceDenom":"denom"}' | ||
*/ | ||
open class UrlGasPrices(private val uri: String) : GasPrices { | ||
private val client = HttpClientBuilder.create().build() | ||
private val gson = Gson().newBuilder().create() | ||
|
||
private data class GasPrice(val gasPrice: Int, val gasPriceDenom: String) { | ||
fun toCoin(): CoinOuterClass.Coin = CoinOuterClass.Coin.newBuilder() | ||
.setAmount(gasPrice.toString()) | ||
.setDenom(gasPriceDenom) | ||
.build() | ||
} | ||
|
||
override fun invoke(): CoinOuterClass.Coin { | ||
val result = client.execute(HttpGet(uri)) | ||
require(result.statusLine.statusCode in 200..299) { | ||
"failed to get uri:$uri status:${result.statusLine.statusCode}: ${result.statusLine.reasonPhrase}" | ||
} | ||
|
||
return result.entity.content.use { i -> | ||
InputStreamReader(i).use { | ||
gson.fromJson(it, GasPrice::class.java).toCoin() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
src/main/kotlin/io/provenance/client/internal/extensions/CoinExtensions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package io.provenance.client.internal.extensions | ||
|
||
import cosmos.base.v1beta1.CoinOuterClass | ||
|
||
internal fun Number.toCoin(denom: String): CoinOuterClass.Coin { | ||
return CoinOuterClass.Coin.newBuilder() | ||
.setAmount(toString()) | ||
.setDenom(denom) | ||
.build() | ||
} | ||
|
||
internal fun String.toCoin(): CoinOuterClass.Coin { | ||
val split = indexOfFirst { it.isLetter() } | ||
require(split != 0) { "invalid amount for coin:$this" } | ||
require(split > 0) { "invalid denom for coin:$this" } | ||
|
||
return CoinOuterClass.Coin.newBuilder() | ||
.setAmount(substring(0, split)) | ||
.setDenom(substring(split, length)) | ||
.build() | ||
} | ||
|
||
internal operator fun List<CoinOuterClass.Coin>.times(other: Double): List<CoinOuterClass.Coin> = map { it * other } | ||
|
||
internal operator fun CoinOuterClass.Coin.times(other: Double): CoinOuterClass.Coin { | ||
return CoinOuterClass.Coin | ||
.newBuilder() | ||
.mergeFrom(this) | ||
.setAmount((amount.toDouble() * other).toBigDecimal().toPlainString()) | ||
.build() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters