fix: transfer invaild txid

This commit is contained in:
hashbro
2026-09-04 04:09:32 +08:00
parent 4c49a61149
commit f67da8a102
16 changed files with 730 additions and 24 deletions
+11
View File
@@ -30,4 +30,15 @@ class TronDriverTest extends TestCase
$this->assertFalse($driver->isValidAddress('0xab5c66752a9e8167967685f1450532fb96d5d24f'));
$this->assertFalse($driver->isValidAddress('Tinvalid'));
}
#[Test]
public function empty_getaccount_payload_is_not_activated(): void
{
$this->assertFalse(TronDriver::accountIsActivated([]));
$this->assertTrue(TronDriver::accountIsActivated([
'address' => 'TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH',
'create_time' => 1,
'balance' => 0,
]));
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
namespace Tests\Unit;
use App\Services\Chain\TronSigner;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use RuntimeException;
use Tests\TestCase;
class TronSignerTest extends TestCase
{
private const PRIVATE_KEY = '0000000000000000000000000000000000000000000000000000000000000001';
#[Test]
#[DataProvider('validTxIds')]
public function signs_valid_txid_without_stripping_leading_zeros(string $txId): void
{
$sig = TronSigner::signTxId(self::PRIVATE_KEY, $txId);
$this->assertMatchesRegularExpression('/^[0-9a-f]{130}$/', $sig);
}
#[Test]
public function rejects_0x_prefixed_txid(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessageMatches('/^Invalid txID \(len=/');
TronSigner::signTxId(self::PRIVATE_KEY, '0x'.str_repeat('ab', 32));
}
#[Test]
public function rejects_truncated_txid_that_old_ltrim_would_produce(): void
{
// Old ltrim(..., '0x') would turn "00ab..." into "ab..." (62 chars).
$this->expectException(RuntimeException::class);
$this->expectExceptionMessageMatches('/^Invalid txID \(len=/');
TronSigner::signTxId(self::PRIVATE_KEY, str_repeat('ab', 31));
}
#[Test]
public function stress_signs_many_leading_zero_txids(): void
{
for ($i = 0; $i < 200; $i++) {
$prefixZeros = random_int(1, 8);
$txId = str_repeat('0', $prefixZeros).bin2hex(random_bytes(32));
$txId = substr($txId, 0, 64);
$this->assertSame(64, strlen($txId));
$this->assertSame('0', $txId[0]);
$sig = TronSigner::signTxId(self::PRIVATE_KEY, $txId);
$this->assertMatchesRegularExpression('/^[0-9a-f]{130}$/', $sig);
}
}
/**
* @return array<string, array{0: string}>
*/
public static function validTxIds(): array
{
return [
'no leading zero' => [str_repeat('ab', 32)],
'one leading zero' => ['0'.str_repeat('a', 63)],
'two leading zeros' => ['00'.str_repeat('b', 62)],
'many leading zeros' => [str_pad('deadbeef', 64, '0', STR_PAD_LEFT)],
'uppercase accepted after lower' => [strtoupper(str_repeat('cd', 32))],
];
}
}
+53
View File
@@ -124,4 +124,57 @@ class WalletBalanceServiceTest extends TestCase
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
}
#[Test]
public function never_activated_trongrid_account_writes_zeros_without_wallet_rpc(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response(['data' => [], 'success' => true], 200),
'*/wallet/*' => Http::response(['should' => 'not be called'], 500),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-inactive-v1',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
]);
$this->assertTrue(app(WalletBalanceService::class)->refresh($addr));
$addr->refresh();
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
Http::assertSentCount(1);
}
#[Test]
public function unactivated_getaccount_skips_usdt_token_call(): void
{
Http::fake([
'*/v1/accounts/*' => Http::response('unavailable', 503),
'*/wallet/getaccount' => Http::response([], 200),
'*/wallet/triggerconstantcontract' => Http::response(['constant_result' => ['ffffff']], 200),
]);
$device = Device::query()->create([
'device_id' => 'dev-bal-inactive-wallet',
'channel_id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
]);
$addr = WalletAddress::query()->create([
'device_id' => $device->id,
'address' => 'TKKyetwdwuv6fTWVMPsdQUZYwB7yiNwRp6',
'chain_type' => 'TRON',
'source' => 'imToken',
]);
$this->assertTrue(app(WalletBalanceService::class)->refresh($addr));
$addr->refresh();
$this->assertEqualsWithDelta(0.0, (float) $addr->trx, 0.0000001);
$this->assertEqualsWithDelta(0.0, (float) $addr->usdt, 0.0000001);
Http::assertNotSent(fn ($request) => str_contains($request->url(), 'triggerconstantcontract'));
}
}